a realtime infrastructure for android apps: firebase may be what you need..and even more!
TRANSCRIPT
Are you looking for a realtime infrastructure behind your mobile app?
Well, Firebase may be what you need..and even more!
DroidconIT2016 – Alessandro Martellucci
I’m Alessandro Martellucci
martellux
+AlessandroMartellucci
@martellux
DroidconIT2016 – Alessandro Martellucci
Open Reply
• Reply is a leading IT Services Company, with offices in Italy, Germany, UK, Benelux, USA, Brazil, France and Poland.
• Open Reply is the company of Reply Group focused on open source software, multichannel solutions and mobile applications.
• From Rome to Milan, our team is based on a young team of over 40 engineers 100% focused on mobile development (iOS, Android & Windows Phone).
• We are specialised in broadcasting, banking, Android OS Customisation, IoT and M2M.
We are hiring! Contact us at [email protected]
DroidconIT2016 – Alessandro Martellucci
Lifecycle 0.2
A binder which let you manage async operations against Android components lifecycle • Seamless execution async-rotation-response • Easily integration with third-party library • No crashes after Activity/Fragment rotation • Fragment transaction management
martellux/Lifecycle com.martellux:lifecycle:0.2.0
DroidconIT2016 – Alessandro Martellucci
Android Programmazione Avanzata
• Multi-screen and multi device development
• Functional Programming with RxJava
• Testing & Code Mantainance
• Android Wear
• Bluetooth Classic & Low Energy
• Google Cast and Chromecast
DroidconIT2016 – Alessandro Martellucci
Agenda
1. What is Firebase 2. NoSQL JSON database 3. Demo 4. Android integration 5. Working with data 6. Working offline 7. FirebaseUI binding 8. Rules management 9. User authentication 10. Pricing
DroidconIT2016 – Alessandro Martellucci
What is Firebase
• MBaaS
• Data synchronization • Hosting (static assets, Node.js)
• Authentication (Google, Facebook, Email & Password, Anonymous)
• Realtime database (JSON)
DroidconIT2016 – Alessandro Martellucci
NoSQL Database
• SQL & RDBMS
• JSON • web format • agile • structure • friendliness
• Drawbacks • navigational query • structure
DroidconIT2016 – Alessandro Martellucci
Firebase JSON
{ “event-name”:”Droidcon Italy”, “location”: { “latitude”:22, “longitude”:22 }, “events”: [ {“name”: “Are you looking for a realtime…”, “speaker”: “Alessandro Martellucci”, “room”: “Sala Parigi”, “time”: 000000 }, … ] }
JSON
DroidconIT2016 – Alessandro Martellucci
Firebase Web Console
DroidconIT2016 – Alessandro Martellucci
Firebase Vulcan Console
DroidconIT2016 – Alessandro Martellucci
DroidconIT 2016 FirebaseDemo
• We’re going live 1. Download app 2. Hit your colour 3. Be patient
DroidconIT2016 – Alessandro Martellucci
Source code at https://github.com/martellux/
Android integration
• Account • Sign with Google
• Dependecies • Right click -> Project Structure -> Cloud -> Firebase
• Reference • Navigation path
DroidconIT2016 – Alessandro Martellucci
Firebase setup (1/2)
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.firebase:firebase-client-android:2.5.1+’ } android { packagingOptions { exclude 'META-INF/LICENSE’ exclude 'META-INF/LICENSE-FIREBASE.txt’ exclude 'META-INF/NOTICE’ } }
Configura.on
DroidconIT2016 – Alessandro Martellucci
Firebase setup (2/2)
public class ApplicationInstance extends Application { @Override public void onCreate() { super.onCreate(); Firebase.setAndroidContext(this); } }
Applica.on
DroidconIT2016 – Alessandro Martellucci
public class MainPresenter extends Presenter { private Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com”); }
Presenter
Reading data
• Callbacks
• Read Type • Value • Child
• Firebase Listener • ValueEventListener • ChildEventListener (added, removed, changed)
DroidconIT2016 – Alessandro Martellucci
Read value changes
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com”); mFirebaseRef.child(“data”).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { Map<String, Object> value = snapshot.getValue(Map.class); //or MyBean myBean = snapshot.getValue(MyBean.class); } @Override public void onCancelled(FirebaseError firebaseError) { Log.e(TAG, "The read failed: " + firebaseError.getMessage()); } });
ValueEventListener
DroidconIT2016 – Alessandro Martellucci
Read new child
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/data”); mFirebaseRef.addChildEventListener(new ChildEventListener() {
@Override public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
MyBean myBean = snapshot.getValue(MyBean.class); String foo = myBean.getFoo(); } @Override public void onCancelled(FirebaseError firebaseError) { Log.e(TAG, "The read failed: " + firebaseError.getMessage()); } });
ChildEventListener
DroidconIT2016 – Alessandro Martellucci
Read child updates
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/data”); mFirebaseRef.addChildEventListener(new ChildEventListener() {
@Override public void onChildChanged(DataSnapshot snapshot, String previousChildKey) {
MyBean myBean = snapshot.getValue(MyBean.class);
Log.d(TAG, ”Prop foo has been updated to: " + myBean.getFoo()); } @Override public void onCancelled(FirebaseError firebaseError) { Log.e(TAG, "The read failed: " + firebaseError.getMessage()); } });
ChildEventListener
DroidconIT2016 – Alessandro Martellucci
Read removed child
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/data”); mFirebaseRef.addChildEventListener(new ChildEventListener() {
@Override public void onChildRemoved(DataSnapshot snapshot) {
MyBean myBean = snapshot.getValue(MyBean.class);
System.out.println(”This entry has been removed: " + myBean.toString()); } @Override public void onCancelled(FirebaseError firebaseError) { System.out.println("The read failed: " + firebaseError.getMessage()); } });
ChildEventListener
DroidconIT2016 – Alessandro Martellucci
Saving Data
• Non-concurrent • Insert • Update
• Concurrent • IDs generation • Transaction
DroidconIT2016 – Alessandro Martellucci
Write or replace data (1/2)
{ …, status: { connectedUsers: 10, ... }, ... }
Onlineusers
DroidconIT2016 – Alessandro Martellucci
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com”); int connectedUsers = countConnectedUsers(); mFirebaseRef.child(“status/connectedUsers”).setValue(connectedUsers);
1)Naviga.ngbysubnodes
Write or replace data (2/2)
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/status”);
int connectedUsers = countConnectedUsers();
mFirebaseRef.child(“connectedUsers”).setValue(connectedUsers);
2)Naviga.ngdirecttonode
DroidconIT2016 – Alessandro Martellucci
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/status”);
Map<String, String> statusMap = new HashMap<String, String>();
statusMap.put(“connectedUsers”, String.valueOf(countConnectedUsers());
mFirebaseRef.setValue(statusMap);
3)UsingMap
Overwrite & delete
JSONnode
DroidconIT2016 – Alessandro Martellucci
{ “status”:{ “connectedUsers”:1, “startTime”:1456426772000, “endTime”:1456426772000 } }
{ “status”:{ “connectedUsers”:1 } }
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/status”); Map<String, String> statusMap = new HashMap<String, String>();
statusMap.put(“connectedUsers”, String.valueOf(countConnectedUsers());
mFirebaseRef.setValue(statusMap);
JavaCode
Update children
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/status”); Map<String, String> statusMap = new HashMap<String, String>(); statusMap.put(“connectedUsers”, String.valueOf(countConnectedUsers()); mFirebaseRef.updateChildren(statusMap);
1)Upda.ngnodes
DroidconIT2016 – Alessandro Martellucci
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com”); Map<String, String> statusMap = new HashMap<String, String>(); statusMap.put(“status/connectedUsers”, String.valueOf(countConnectedUsers());
mFirebaseRef.updateChildren(statusMap);
2)Upda.ngsubnodes
Concurrent-indipendent insert
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com”); Firebase dataChildRef = mFirebaseRef.child(“data”); Firebase newChildRef = dataChildRef.push();
Map<String, Object> colorMap = new HahsMap<String, Object>(); colorMap.put(“red”, “242”); colorMap.put(“green”, “10”); colorMap.put(“blue”, “22”); newChildRef .setValue(colorMap);
JavaCode
DroidconIT2016 – Alessandro Martellucci
Concurrent-dipendent insert
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/data”); newChildRef.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData currentData) { if((currentData.getValue() == null) { currentData.setValue(1); } else { currentData.setValue((Long) currentData.getValue() + 1); } return Transaction.success(currentData); } @Override public void onComplete(FirebaseError error, boolean committed, DataSnapshot currentData) { … } });
JavaCode
DroidconIT2016 – Alessandro Martellucci
Working offline
• Works offline
• Seamless experience
• Auto synchronization
DroidconIT2016 – Alessandro Martellucci
User authentication
DroidconIT2016 – Alessandro Martellucci
• User identification • Email & password login
• Easy integration • Facebook, GitHub, Google and Twitter
• Session management • Single session • Custom token
FirebaseUI - Authentication
DroidconIT2016 – Alessandro Martellucci
1. Add SDK dependencies 2. Add Facebook/Twitter/Google keys to
strings.xml 3. Change our AndroidManifest.xml 4. Inherit from FirebaseLoginBaseActivity 5. Enable authentication providers 6. Call showFirebaseLoginDialog();
Facebook authentication
DroidconIT2016 – Alessandro Martellucci
Firebase mFirebaseRef = new Firebase(“https://droidconit2016-demo.firebaseio.com/data”); mFirebaseRef .addAuthStateListener(new Firebase.AuthStateListener() { @Override public void onAuthStateChanged(AuthData authData) { if (authData != null) { // user is logged in Map<String, String> map = new HashMap<String, String>(); map.put("provider", authData.getProvider()); if(authData.getProviderData().containsKey("displayName")) { map.put("displayName", authData.getProviderData().get("displayName").toString()); } ref.child("users").child(authData.getUid()).setValue(map); } else { // user is not logged in } } });
Authen.ca.on
Rules management (1/2)
DroidconIT2016 – Alessandro Martellucci
{ "rules": { ".read": true, ".write": true } }
Basicrules
• JavaScript-like
• Node permissions • Node validations
Rules management (2/2)
DroidconIT2016 – Alessandro Martellucci
{ “status”: { “schedule”: { “startTime”: 123456670292, … } } }
startTimenode
{ "rules": { "status": { "schedule": { "startTime": { // readable ".read": true, // data written must be a number ".validate": "newData.isNumber()”, // write authorization ".write": "$user_id === auth.uid” }}}}}
RulesforstartTimenode
FirebaseUI
DroidconIT2016 – Alessandro Martellucci
• Open source library • iOS support
• Authentication
• built-in dialog • List binding
• ListView • RecyclerView
FirebaseUI – ListView
DroidconIT2016 – Alessandro Martellucci
@Override protected void onCreate(Bundle savedInstanceState) { … ListView messagesView = (ListView) findViewById(R.id.messages_list); mAdapter = new FirebaseListAdapter<MyBean>(this, MyBean.class, R.layout.my_list_item, mFirebaseRef) { @Override protected void populateView(View view, MyBean myBean, int position) { ((TextView)view.findViewById(android.R.id.text1)).setText(myBean.getFoo()); } }; messagesView.setAdapter(mAdapter); }
Adapter
FirebaseUI – RecyclerView
DroidconIT2016 – Alessandro Martellucci
@Override protected void onCreate(Bundle savedInstanceState) { … RecyclerView recycler = (RecyclerView) findViewById(R.id.messages_recycler); recycler.setHasFixedSize(true); recycler.setLayoutManager(new LinearLayoutManager(this)); mAdapter = new FirebaseRecyclerAdapter<MyBean, MyBeanViewHolder>(MyBean.class, R.layout.my_line_list_item, MyBeanViewHolder.class, mFirebaseRef) { @Override public void populateViewHolder(MyBeanViewHolder myBeanViewHolder, MyBean myBean, int position) { myBeanViewHolder.nameText.setText(myBean.getFoo()); } }; recycler.setAdapter(mAdapter); }
Adapter
Pricing
DroidconIT2016 – Alessandro Martellucci
FREE(0$forever)
SPARK(5$month)
… INFERNO(1499$month)
DBconnec.ons 100 100 … UNLIMITED
DBstorage 1GB 1GB … 300GB
DBtransfer 10GB 10GB … 1.5TB
PrivateBackups NO NO … YES
Authen.ca.on UNLIMITEDUSERS
UNLIMITEDUSERS … UNLIMITED
USERS
Hos.ngStorage 1GB 1GB … 10GB
Hos.ngTransfer 100GB 100GB … 1TB
CustomDomain NO YES … YES
Resources
• BLOG: https://www.firebase.com/blog
• Twitter: @firebase
• Facebook: Firebase
• Google Plus: Firebase
• Official: http://www.firebase.com
• Github: https://github.com/firebase
• YouTube: Firecast: Firebase Screencast
DroidconIT2016 – Alessandro Martellucci
THANK YOU ALL
DroidconIT2016 – Alessandro Martellucci