WorryFree Computers   »   [go: up one dir, main page]

Hiranya Jayathilaka
Hiranya Jayathilaka
Software Engineer

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.

Initializing the Admin SDK for Go

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)

Minting Custom Tokens and Verifying ID Tokens

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.

What's Next?

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!

Originally Posted by David Ohayon, Software Engineer on the Fabric Blog

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!

Speeding up screenshots (even more!)

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:

More exciting updates on the way

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!

Doug Stevenson
Doug Stevenson
Developer Advocate
If you've browsed the web at all, you've probably seen some sites that ask you to prove you're a human by presenting a reCAPTCHA challenge. For example, if you try to use the goo.gl URL shortener, it won't let you shorten a link until you satisfy the reCAPTCHA, which looks like this:

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.

1. Create a Firebase project in the console

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.

2. Set up a directory for your project code

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.

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.

3. Test web deployment

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".

4. Get a reCAPTCHA API Key

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.

5. Add a page with a reCAPTCHA

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:

<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 = "/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!

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.

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.

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.

6. Create a Cloud Function to verify the reCAPTCHA response

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:

  1. The reCAPTCHA verifies successfully (the user is human)
  2. The reCAPTCHA fails (could be a robot)
  3. The API call fails altogether

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!

7. Add rewrites to map a hosting URL to a Cloud Function

Edit the file firebase.json in the project root directory and paste the follow JSON configuration as its contents:

{
  "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.

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:

$ firebase deploy

8. Test the reCAPTCHA!

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."

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.

Ibrahim Ulukaya
Ibrahim Ulukaya
Developer Programs Engineer

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!

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.

How to use

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.

Happy coding!

Darin Hilton
David DeRemer
Originally posted on the Google Developers Blog by David DeRemer (from Posse)

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.

The Cloud Where It Happens

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.

What'd I miss?

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!

Cloud Functions Left Us Satisfied

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.

Developing UI? Don't Wait For It.

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.

What comes next?

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.

Darin Hilton
Darin Hilton
Art Director
So much goes into building and maintaining a mobile game. Let's say you want to ship it with a level builder for sharing content with other players and, looking forward, you want to roll out new content and unlockables linked with player behavior. Of course, you also need players to be able to easily sign into your soon-to-be hit game.

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.

Analytics

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.

Test Lab for Android - Game Loop Test

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.

Authentication

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.

Remote Config

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.

Realtime Database

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.

Cloud Messaging & Dynamic Links

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.

Doug Stevenson
Doug Stevenson
Developer Advocate
There are a couple recent changes to the way you build your Android apps with Google Play services (and Firebase SDKs, which are distributed as part of Play services). Here's what you need to know to stay up to date.

1. Play services (and Firebase) dependencies are now available via maven.google.com

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.

You can read more about Google's maven repo here.

2. Starting with Play services dependencies version 11.2.0, your app's compileSdkVersion must be at least 26

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:

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.

Frank van Puffelen
Frank van Puffelen
Engineer
We're excited to announce that the registration for the Firebase Dev Summit is opening today!

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.

I had a blast at last year's Dev Summit in Berlin

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.

What is the Firebase Dev Summit?

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!

Doug Stevenson
Doug Stevenson
Developer Advocate

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):

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:

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.