The Firebase Admin SDK for Go is now generally available. This is the fourth programming language to join our growing family of Admin SDKs, which already includes support for Java, Python and Node.js. Firebase Admin SDKs enable application developers to programmatically access Firebase services from trusted environments. They complement the Firebase client SDKs, which enable end users to access Firebase from their web browsers and mobile devices. The initial release of the Firebase Admin SDK for Go comes with some Firebase Authentication features: custom token minting and ID token verification.
Similar to the other Firebase Admin SDKs, the Go Admin SDK can be initialized with a variety of authentication credentials and client options. The following code snippet shows how to initialize the SDK using a service account credential obtained from the Firebase console or the Google Cloud console:
import ( "golang.org/x/net/context" firebase "firebase.google.com/go" "google.golang.org/api/option" ) opt := option.WithCredentialsFile("path/to/key.json") app, err := firebase.NewApp(context.Background(), nil, opt)
If you are running your code on Google infrastructure, such as Google App Engine or Google Compute Engine, the SDK can auto-discover application default credentials from the environment. In this case you do not have to explicitly specify any credentials when initializing the Go Admin SDK:
import ( "golang.org/x/net/context" firebase "firebase.google.com/go" ) app, err := firebase.NewApp(context.Background(), nil)
The initial release of the Firebase Admin SDK for Go comes with support for minting custom tokens and verifying Firebase ID tokens. The custom token minting allows you to authenticate users using your own user store or authentication mechanism:
client, err := app.Auth() if err != nil { return err } claims := map[string]interface{}{ "premium": true, "package": "gold", } token, err := client.CustomToken("some-uid", claims)
The resulting custom token can be sent to a client device, where it can be used to initiate an authentication flow using a Firebase client SDK. On the other hand, the ID token verification facilitates securely identifying the currently signed in user on your server:
client, err := app.Auth() if err != nil { return err } decoded, err := client.VerifyIDToken(idToken) uid := decoded.UID
To learn more about using the Firebase Admin SDK for Go, see our Admin SDK setup guide.
We plan to further expand the capabilities of the Go Admin SDK by implementing other useful APIs such as user management and Firebase Cloud Messaging. This SDK is also open source. Therefore we welcome you to browse our Github repo and get involved in the development process by reporting issues and sending pull requests. To all Golang gophers out there, happy coding with Firebase!
Every mobile developer needs to take app screenshots in order to have their app listed on the app stores. Like a book cover, screenshots are crucial in depicting the best parts of your app and convincing potential users to download it.
Unfortunately, generating app screenshots is a huge pain because they take a ton of time, especially if your app supports different locales and languages. For example, if you need to take 5 screenshots for your app store listing - but your app supports 20 languages for 6 devices - you'll manually have to take 600 screenshots (5 x 20 x 6)! It makes us shudder to think how many precious hours that would eat up.
fastlane's snapshot tool automates the process of taking screenshots (in the background) so you can focus on building features users love. Today, we're excited to share that snapshot now supports multiple, concurrent simulators for iOS apps in Xcode 9. Taking screenshots just got even faster because you can now generate screenshots for all of your devices at the same time!
Before Xcode 9, only one simulator could be running at a time, which means that you had to run snapshot once for each device you wish to support. While snapshot automated the process of taking screenshots, we wanted to make things even easier.
The launch of Xcode 9 gave us another opportunity to improve snapshot. In Xcode 9, multiple UI tests can run simultaneously, so we added multiple simulator support to snapshot as well. Now, you can take screenshots for all specified devices with a single command, at the same time. This drastically shortens the time it takes to generate your screenshots.
Here's an example:
fastlane's mission is to save you time by automating the cumbersome tasks of app deployment, even as mobile evolves. That's why we're fully committed to updating the fastlane toolset to take advantage of new releases and features - such as Xcode 9.
And since fastlane is open source, we're so thankful that our community also helps us make fastlane better by building and using plugins. In fact, we now have more user-generated plugins available for you to try than native fastlane actions. We recently reorganized these plugins to make it easier to find the right plugins for your unique needs.
We always strive to anticipate your needs and build our tools to be ready for the future. To start using the new version of snapshot, simply update fastlane and run snapshot as you normally would. If you're taking screenshots manually, check out our guide to start using snapshot (and enjoy the extra free time!). As always, we can't wait to hear what you think!
Web site engineers do this to protect their site from spam and abuse from bots, while allowing legitimate human use. Why is protection needed? Maybe you have some backend code that's expensive in time and storage and you only want actual users of your web to access it.
If you have a web site, you can also use reCAPTCHA to protect its services. And, if you're building your site with Firebase Hosting, it's pretty easy to get it integrated with the help of Cloud Functions for Firebase to provide a secure, scalable backend to verify the completion of the reCAPTCHA.
In this blog post, I'll walk you through a few steps that will get you to a very basic integration that you can extend later for your own site. For this walkthrough, I'm assuming you already have some experience with web development, the Firebase console, and the Firebase CLI.
Navigate to the Firebase console and create a new project. There's no need to add billing to this project - you can experiment fully without providing a credit card. Once you create the project, there's nothing else you need to do in the console.
Using the Firebase CLI, make sure you're logged in with the same Google account that you used to create the project:
$ firebase login
Now, create a root project directory and initialize it:
$ mkdir my_project $ cd my_project $ firebase init
When running firebase init, be sure to select both hosting and functions. When you're asked to choose a project, select the one you just created earlier. Take the defaults for every other prompt. You'll end up with a directory structure that contains a public folder for web content, and a functions folder for your backend code.
firebase init
public
functions
For the Cloud Functions backend, we'll need a couple modules from npm to help verify the reCAPTCHA. The reCAPTCHA API requires you to make an HTTP request for verification from your backend, and you can do that with the request and request-promise modules. Pull them into your project like this:
$ cd functions $ npm install request request-promise
Your package.json file should now show those two new modules in addition to firebase-functions and firebase-admin.
package.json
Make sure you can deploy web content by running this deploy command:
$ firebase deploy --only hosting
When this finishes, you'll be given the public URL to your new web site, which will look something like this:
✔ Deploy complete! Project Console: https://console.firebase.google.com/project/your-project/overview Hosting URL: https://your-project.firebaseapp.com
where your-project is the unique id that was given to your project at the time it was created in the console. If you paste the Hosting URL into your browser, you should see a page that says "Firebase Hosting Setup Complete".
your-project
reCAPTCHA requires a couple API keys for operation, one for the web client and one for the server API. You can get those from the reCAPTCHA admin panel, so navigate there. Create a new site and give it a name. Select "reCAPTCHA V2". For domains, put the full hostname of your Firebase Hosting site name (e.g. "your-project.firebaseapp.com").
After you register, you'll be given a Site key and a Secret key. The Site key will be used in your frontend HTML, and the Secret key will be used in your backend hosted by Cloud Functions.
Now we'll add a new HTML page to display the reCAPTCHA. In the public directory in your project, add a new HTML file called recaptcha.html to display the reCAPTCHA. Simply copy and paste the following content directly into that new file:
recaptcha.html
<html> <head> <title>Firebase + reCAPTCHA</title> <script src="https://www.google.com/recaptcha/api.js" async defer></script> <script type="text/javascript"> function dataCallback(response) { console.log("dataCallback", response) window.location.href="/https/firebase.googleblog.com/checkRecaptcha?response=" + encodeURIComponent(response) } function dataExpiredCallback() { console.log("dataExpiredCallback") } </script> </head> <body> <div class="g-recaptcha" data-sitekey="PASTE_YOUR_SITE_KEY_HERE" data-callback="dataCallback" data-expired-callback="dataExpiredCallback"/> </body> </html>
Notice in the body there is a div with the class "g-recaptcha". The first thing you should do here is copy your reCAPTCHA site key into the div's data-sitekey attribute value. This div will get automatically transformed into a reCAPTCHA UI after the first script at the top is loaded. You can read more about that here in the docs.
You can see it right away if you firebase deploy again, then navigate to /recaptcha.html under your Hosting URL. Don't bother dealing with the reCAPTCHA yet, because we still need some backend code to complete the verification!
firebase deploy
The JavaScript code in this page defines two functions dataCallback and dataExpiredCallback. These are referenced in the div, and provide callbacks for the reCAPTCHA to tell you when the reCAPTCHA has been satisfied, or if the user took too long to proceed.
dataCallback
dataExpiredCallback
The important thing to note in dataCallback is that it redirects the browser to another URL in the site with the path /checkRecaptcha, and pass it a parameter named response. This response string is generated by reCAPTCHA and looks like a random collection of characters.
/checkRecaptcha
response
The path /checkRecaptcha in your web site obviously doesn't exist yet, so we need to create a Cloud Function to validate the response string it's going to receive.
In the functions directory in your project, edit the existing index.js file. This has some sample code, but you can delete it. In its place, paste the following JavaScript code:
const functions = require('firebase-functions') const rp = require('request-promise') exports.checkRecaptcha = functions.https.onRequest((req, res) => { const response = req.query.response console.log("recaptcha response", response) rp({ uri: 'https://recaptcha.google.com/recaptcha/api/siteverify', method: 'POST', formData: { secret: 'PASTE_YOUR_SECRET_CODE_HERE', response: response }, json: true }).then(result => { console.log("recaptcha result", result) if (result.success) { res.send("You're good to go, human.") } else { res.send("Recaptcha verification failed. Are you a robot?") } }).catch(reason => { console.log("Recaptcha request failure", reason) res.send("Recaptcha request failed.") }) })
The first thing you should do here is paste your reCAPTCHA secret key from the registration site in place of "PASTE_YOUR_SECRET_CODE_HERE".
(Astute readers may note that the reCAPTCHA API endpoint host is "recaptcha.google.com", while the docs say "www.google.com". This is OK! You have to use recaptcha.google.com as shown in order to make the call on the Spark plan, because that host has been whitelisted for outgoing traffic from Cloud Functions.)
This code defines an HTTPS function that, when triggered, will make another HTTPS request (using the request-promise module) to the reCAPTCHA API in order to verify the response that was received in the query string. Notice that there are three cases with three different responses to the client. Either:
It's important to send a response to the client in all cases, otherwise the function will time out with an error message in the Firebase console log.
To deploy this new function (and the web content at the same time) run the following command:
$ firebase deploy
You'll notice in the output that the function is assigned its own URL, which looks something like this:
https://us-central1-your-project.cloudfunctions.net/checkRecaptcha
This is clearly a different host than the one with your web content. However, what we really want instead is for the function to be referenced through your web host at a URL that looks like this:
https://your-project.firebaseapp.com/checkRecaptcha
This makes the function look like it's part of your web site. With Firebase Hosting a Cloud Functions, this can be done!
Edit the file firebase.json in the project root directory and paste the follow JSON configuration as its contents:
firebase.json
{ "hosting": { "public": "public", "rewrites": [ { "source": "/checkRecaptcha", "function": "checkRecaptcha" } ] } }
What you've done here is add a new section for rewrites, and you can read more about those in the docs. Specifically what this does is allow access to the URL path /checkRecaptcha invoke the function called checkRecaptcha that you pasted into your functions/index.js file.
checkRecaptcha
functions/index.js
Remember that the JavaScript code in recaptcha.html redirects to this path when the reCAPTCHA is satisfied by the user, so this effectively sends to user to the function after they complete the reCAPTCHA.
Now do one final deploy to send everything to Firebase:
Navigate to /recaptcha.html under your hosting URL, then solve the reCAPTCHA. It may ask you to identify some cars or roads in a set of pictures. Once you've satisfied the reCAPTCHA with your humanity, the JavaScript in your HTML should redirect you to your function, which verifies with the server that you're indeed human, and you should see the message "You're good to go, human."
/recaptcha.html
This example of how to use reCAPTCHA with Cloud Functions for Firebase is much more simple than what you'd probably do in your own web site. You have several options for how to send the reCAPTCHA response to your function, and you'd obviously want to provide something more useful than a message to the user. But this should get you started protecting your web content from abuse from bots.
Ever spend an hour wondering why Remote Config wasn't working, only to realize that you forgot to call activateFetched? Or didn't read a Dynamic Link because you forgot to implement the application:continue:restorationHandler method? Well, now there's a tool to help stop those mistakes before they happen!
activateFetched
application:continue:restorationHandler
SwiftLint is a great open source tool that makes it easier for you to follow Swift style and conventions. It also helps with identifying possible errors early by highlighting problematic usage. You can run SwiftLint on your Xcode project to see all the style guide exceptions on the lines where they occur, and fix them quickly. I found it was a great help when I migrated my code from Objective-c to Swift.
In the spirit of making SwiftLint even more useful for Firebase developers, we've added some experimental new Firebase rules into SwiftLint. These rules will display warnings on common mistakes that might lead to errors when using the Firebase SDK.
Currently we are hosting the rules on our fork in a firebase_rules branch. Our pre-release binary holds the Firebase rules. You simply download the .pkg file and double click to install. You can also build the binary from the source.
Since the rules are opt-in, you'll need to add a .swiftlint.yml file in the same folder as your Swift source files, containing the following text:
``` opt_in_rules: - firebase_config_activate - firebase_config_defaults - firebase_config_fetch - firebase_core - firebase_dynamiclinks_customschemeURL - firebase_dynamiclinks_schemeURL - firebase_dynamiclinks_universallink - firebase_invites ```
Then, just run SwiftLint on your project like normal.
If you're interested in how we put the rules together, you can read our post with all the development details.
We'd love for you to give it a try and send us feedback on Twitter with #FirebaseLinter. You can also ask questions on StackOverflow using the firebase and swiftlint tags together.
firebase
swiftlint
Whether it's opening night for a Broadway musical or launch day for your app, both are thrilling times for everyone involved. Our agency, Posse, collaborated with Hamilton to design, build, and launch the official Hamilton app... in only three short months.
We decided to use Firebase, Google's mobile development platform, for the backend and infrastructure, while we used Flutter, a new UI toolkit for iOS and Android, for the front-end. In this post, we share how we did it.
We love to spend time designing beautiful UIs, testing new interactions, and iterating with clients, and we don't want to be distracted by setting up and maintaining servers. To stay focused on the app and our users, we implemented a full serverless architecture and made heavy use of Firebase.
A key feature of the app is the ticket lottery, which offers fans a chance to get tickets to the constantly sold-out Hamilton show. We used Cloud Functions for Firebase, and a data flow architecture we learned about at Google I/O, to coordinate the lottery workflow between the mobile app, custom business logic, and partner services.
For example, when someone enters the lottery, the app first writes data to specific nodes in Realtime Database and the database's security rules help to ensure that the data is valid. The write triggers a Cloud Function, which runs business logic and stores its result to a new node in the Realtime Database. The newly written result data is then pushed automatically to the app.
Because of Hamilton's intense fan following, we wanted to make sure that app users could get news the instant it was published. So we built a custom, web-based Content Management System (CMS) for the Hamilton team that used Firebase Realtime Database to store and retrieve data. The Realtime Database eliminated the need for a "pull to refresh" feature of the app. When new content is published via the CMS, the update is stored in Firebase Realtime Database and every app user automatically sees the update. No refresh, reload, or pull required!
Besides powering our lottery integration, Cloud Functions was also extremely valuable in the creation of user profiles, sending push notifications, and our #HamCam — a custom Hamilton selfie and photo-taking experience. Cloud Functions resized the images, saved them in Cloud Storage, and then updated the database. By taking care of the infrastructure work of storing and managing the photos, Firebase freed us up to focus on making the camera fun and full of Hamilton style.
With only three months to design and deliver the app, we knew we needed to iterate quickly on the UX and UI. Flutter's hot reload development cycle meant we could make a change in our UI code and, in about a second, see the change reflected on our simulators and phones. No rebuilding, recompiling, or multi-second pauses required! Even the state of the app was preserved between hot reloads, making it very fast for us to iterate on the UI with our designers.
We used Flutter's reactive UI framework to implement Hamilton's iconic brand with custom UI elements. Flutter's "everything is a widget" approach made it easy for us to compose custom UIs from a rich set of building blocks provided by the framework. And, because Flutter runs on both iOS and Android, we were able to spend our time creating beautiful designs instead of porting the UI.
The FlutterFire project helped us access Firebase Analytics, Firebase Authentication, and Realtime Database from the app code. And because Flutter is open source, and easy to extend, we even built a custom router library that helped us organize the app's UI code.
We enjoyed building the Hamilton app (find it on the Play Store or the App Store) in a way that allowed us to focus on our users and experiment with new app ideas and experiences. And based on our experience, we'd happily recommend serverless architectures with Firebase and customized UI designs with Flutter as powerful ways for you to save time building your app.
For us, we already have plans how to continue and develop Hamilton app in new ways, and can't wait to release those soon!
If you want to learn more about Firebase or Flutter, we recommend the Firebase docs, the Firebase channel on YouTube, and the Flutter website.
With a DIY approach, you'd be faced with having to build user management, data storage, server side logic, and more. This will take a lot of your time, and importantly, it would take critical resources away from what you really want to do: build that amazing new mobile game!
Our Firebase SDKs for Unity and C++ provide you with the tools you need to add these features and more to your game with ease. Plus, to help you better understand how Firebase can help you build your next chart-topper, we've built a sample game in Unity: MechaHamster. Check it out on Google Play or download the sample project at Github to see how easy it is to integrate Firebase into your game.
Before you dive into the sample code for MechaHamster, here's a rundown of the Firebase products that can help your game be successful.
One of the best tools you have to maintain a high-performing game is your analytics. With Google Analytics for Firebase, you can see where your players might be struggling and make adjustments as needed. Analytics also integrates with Adwords and other major ad networks to maximize your campaign performance. If you monetize your game using AdMob, you can link your two accounts and see the lifetime value (LTV) of your players, from in-game purchases and AdMob, right from your Analytics console. And with Streamview, you can see how players are interacting with your game in realtime.
Before releasing updates to your game, you'll want to make sure it works correctly. However, manual testing can be time consuming when faced with a large variety of target devices. To help solve this, we recently launched Firebase Test Lab for Android Game Loop Test at Google I/O. If you add a demo mode to your game, Test Lab will automatically verify your game is working on a wide range of devices. You can read more in our deep dive blog post here.
Another thing you'll want to be sure to take care of before launch is easy sign-in, so your users can start playing as quickly as possible. Firebase Authentication can help by handling all sign-in and authentication, from simple email + password logins to support for common identity providers like Google, Facebook, Twitter, and Github. Just announced recently at I/O, Firebase also now supports phone number authentication. And Firebase Authentication shares state cross-device, so your users can pick up where they left off, no matter what platforms they're using.
As more players start using your game, you realize that there are few spots that are frustrating for your audience. You may even see churn rates start to rise, so you decide that you need to push some adjustments. With Firebase Remote Config, you can change values in the console and push them out to players. Some players having trouble navigating levels? You can adjust the difficulty and update remotely. Remote Config can even benefit your development cycle; team members can tweak and test parameters without having to make new builds.
Now that you have a robust player community, you're probably starting to see a bunch of great player-built levels. With Firebase Realtime Database, you can store player data and sync it in real-time, meaning that the level builder you've built can store and share data easily with other players. You don't need your own server and it's optimized for offline use. Plus, Realtime Database integrates with Firebase Auth for secure access to user specific data.
A few months go by and your game is thriving, with high engagement and an active community. You're ready to release your next wave of new content, but how can you efficiently get the word out to your users? Firebase Cloud Messaging lets you target messages to player segments, without any coding required. And Firebase Dynamic Links allow your users to share this new content — or an invitation to your game — with other players. Dynamic Links survive the app install process, so a new player can install your app and then dive right into the piece of content that was shared with him or her.
At Firebase, our mission is to help mobile developers build better apps and grow successful businesses. When it comes to games, that means taking care of the boring stuff, so you can focus on what matters — making a great game. Our mobile SDKs for C++ and Unity are available now at firebase.google.com/games and don't forget to check out our sample game project, MechaHamster, on GitHub.
Until recently, developers were required to update their Android tools to make use of new versions of the local maven repository that contains Play services compile dependencies. Only after updating were the Android build tools able to locate them. Now, the dependencies are available directly from maven.google.com. You can update your app's Gradle build scripts to use this repository by simply configuring the build like this:
allprojects { repositories { jcenter() maven { url 'https://maven.google.com' } } }
Note the new Google maven repository. This is where dependencies are now hosted. Using Gradle 4.0 and later, you can simply specify google() as a shortcut instead. Once configured like this, Gradle will be able to locate, download, and cache the correct Play services dependencies without requiring an update to the Android build tools. Play services SDKs going back to version 3.1.36 will be available in this repo.
google()
You can read more about Google's maven repo here.
compileSdkVersion
When you upgrade your app's Play services dependencies to 11.2.0 or later, your app's build.gradle must also be updated to specify a compileSdkVersion of at least 26 (Android O). This will not change the way your app runs. You will not be required to update targetSdkVersion. If you do update compileSdkVersion to 26, you may receive an error in your build with the following message referring to the Android support library:
build.gradle
targetSdkVersion
This support library should should not use a different version (25) than the compileSdkVersion (26).
This error can be resolved by upgrading your support library dependencies to at least version 26.0.0. Generally speaking, the compileSdkVersion of your app should always match the major version number of your Android support library dependencies. In this case, you'll need to make them both 26.
Please join us in Amsterdam on October 31st for a day of talks, codelabs, and office hours, as well as (of course) an after-party.
Three months ago, thousands of developers joined us at Google I/O to hear about improvements to the Firebase platform, like Performance Monitoring, Phone Authentication, and our newly open sourced SDKs. We haven't slowed down since then and now we're excited to bring the Firebase and Fabric teams to Amsterdam to talk about a bunch of new announcements, as well as hear your feedback on how we can improve Firebase to help you build even more extraordinary experiences for your users.
Registration is now open, but keep in mind that space will be filled on a first-come, first-serve basis, so make sure to request an invitation today.
The Firebase Dev Summit is full day event for app developers that will focus on solving core infrastructure and growth challenges in app development. We'll have deep dive sessions, as well as introductory overviews, so all levels of Firebase familiarity are welcome!
We also want you to get your hands dirty with Firebase. You'll get a chance to put your new knowledge into practice with instructor-led codelabs, as well as ask our team any questions you have at our #AskFirebase lounge.
The day isn't just about us talking to to you, though. Our product managers and engineering team (including me!) are excited to meet you in person and hear your feedback about what is and isn't working in Firebase. Our community is what makes Firebase great, so we couldn't be more excited to get your help in shaping the future of Firebase.
As a native Dutchie, I'm thrilled that we'll be combining two of my favorite things at the Dev Summit this year: Firebase & The Netherlands! If you'll be traveling to Amsterdam for the conference, I highly recommend you stay an extra day. Take a canal tour, visit one of the many museums, rent a bike, or just take a stroll and say hi to a local. We're friendly, I promise :-).
We're looking forward to meeting you in person. Dank je en tot gauw!
If you haven't tried Firebase Performance Monitoring yet, many Firebase developers have found it to be a helpful way to get a sense of some of the performance characteristics of their iOS or Android app, without writing many extra lines of code. To get more detailed information beyond what's collected automatically, you'll eventually have to write some custom traces and counters. Traces are a report of performance data within a distinct period of time in your app, and counters let you measure performance-related events during a trace. In today's perf tip, I'll propose a way to add potentially many more traces to your Android app without writing very much code at all.
Android apps are typically made up of a collection of activities that present some task or data to the user. For the purpose of hunting down potential performance problems, it can be handy to define a trace for every Activity in your app, so you can study the results later in the Firebase console. If your app has lots of activities, it might be kind of a pain to write the code for all of them. Instead, you can write a little bit of code that instruments all of them with their own trace.
Android gives you a way to listen in on the lifecycle of every single Activity in your app. The listeners are implementations of the interface ActivityLifecycleCallbacks, and you can register one with the Application.registerLifecycleCallbacks() method. For measuring performance, I suggest creating a trace that corresponds to the onStart() and onStop() lifecycle methods. When an activity is "started", that means it's visible on screen, and when it's "stopped", it's no longer visible, so I think this is a good place to define a trace that tracks an activity while it's actually doing things. Here's the start of an implementation of ActivityLifecycleCallbacks that keeps track of traces for each of your activities. First we'll make it a singleton so it can be easily accessed everywhere (or you might want to use some form of dependency injection):
ActivityLifecycleCallbacks
Application.registerLifecycleCallbacks()
onStart()
onStop()
public class PerfLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { private static final PerfLifecycleCallbacks instance = new PerfLifecycleCallbacks(); private PerfLifecycleCallbacks() {} public static PerfLifecycleCallbacks getInstance() { return instance; } }
Then, inside that class, I'll add some members that manage custom traces for each Activity:
private final HashMap<Activity, Trace> traces = new HashMap<>(); @Override public void onActivityStarted(Activity activity) { String name = activity.getClass().getSimpleName(); Trace trace = FirebasePerformance.startTrace(name); traces.put(activity, trace); } @Override public void onActivityStopped(Activity activity) { Trace trace = traces.remove(activity); trace.stop(); } // ...empty implementations of other lifecycle methods...
This will start a trace when any activity is started, and stop the same trace when the activity is stopped. For the name of the trace, I'm using the simple class name of the activity object, which is just the class name without the full java package. (Note: if you do this, make sure that your Activity class names are unique, if they're spread across Java packages!)
I'll add one more method to it that will return the trace of a given Activity object. That can be used in any activity to get a hold of the current trace so that counters can be added to it:
@Nullable public Trace getTrace(Activity activity) { return traces.get(activity); }
This class should be registered before any Activity starts. A ContentProvider is a good place to do that. If you're not familiar with how that works, you can read about how Firebase uses a ContentProvider to initialize.
public class PerfInitContentProvider extends ContentProvider { @Override public boolean onCreate() { context = getContext(); if (context != null) { Application app = (Application) context.getApplicationContext(); app.registerActivityLifecycleCallbacks( PerfLifecycleCallbacks.getInstance()); } } }
Don't forget to add the ContentProvider to your app's manifest! This will ensure that it gets created before any Activity in your app.
Once this ContentProvider is in place, your app will automatically create traces for all your activities. If you want to add counters to one of them, simply use the getTrace() method from the PerfLifecycleCallbacks singleton using the current Activity object. For example:
getTrace()
private Trace trace; @Override protected void onCreate(Bundle savedInstanceState) { trace = PerfLifecycleCallbacks.getInstance().getTrace(this); // use the trace to tally counters... }
Be sure to think carefully about the counters you want to log! You'll want to measure things that will give you information that helps inform a decision about how the user experience could be improved in your app. For example, you could record the ratio of cache hits to misses to help tune the amount of memory for the cache. And be sure to follow Firebase on Twitter to get more Firebase Performance Monitoring tips.