With so much time spent on game development, the last thing any game developer wants to see is a low rating as a result of a buggy game. From our very first Crashlytics NDK release back in 2015, our commitment to game developers remains strong. And recently we released a number of NDK and Unity features that not only increase the stability of games, but also enable developers using Unreal, Cocos2d, Unity or any other native game engine to get to resolutions quickly and with more confidence. Read more about these improvements below.
To provide you with a more accurate view into the stability of your gaming apps, we’ve made significant changes to Crashlytics' native crash capture mechanism by adopting Google's open-source Crashpad library. As a result, you can now get access to several additional classes of errors on newer Android versions as well as get more reliable crash reporting on existing Android versions of your app. Additionally, with Crashpad you no longer have to deal with the inherent complexity of native crash capture and instead you can focus your time on growing your game.
The increased reliability of Crashpad lies in its pursuit of minimizing the amount of work done within the signal handler, which ultimately results in a more reliable crash capturing mechanism. One of Crashpad’s core design goals is to reduce the number of system calls inside the handler to just one. Upon receiving a signal, Crashpad captures the memory space of the crashed application by launching a brand new, healthy process, removing some of the problems of other crash capture approaches such as capturing SIGABRT on Android 10+ devices.
More accurate stack traces, especially within the application frames, lead to faster issue resolutions - there is no doubt about it! That is why we’ve switched our symbol file format to one that is more robust - the Breakpad symbol file. The additional debug information within the Breakpad symbol file, in many circumstances, results in a more accurate stack trace than what you’d see in the logcat.
The key to more accurate stack traces lies within the Call Frame Information that is stored within the debug section of the binaries. This information is what differentiates the Breakpad symbol file from our previous symbol file. Call frame information assists our backend stack unwinding process, minimizing the use of heuristics within application frames that may lead to incorrect stack traces. With this information, our backend more precisely determines how the frames within your application should be unwound and which symbols - inlined or not - correspond to each frame!
Take a look at the Google Games Developer Summit session that explains this in more detail. If you’re already using the Crashlytics NDK SDK, switching to the Breakpad symbol file is a breeze, just add symbolGenerator { breakpad() } to your build.gradle. Check out our docs for more info.
symbolGenerator { breakpad() }
The left image shows a stack that is unwound using our previous symbol format, and the right image shows the same stack unwound using the Breakpad symbol file.
The top image shows a frame symbolicated using our previous symbol format, and the bottom image shows the same frame symbolicated using the Breakpad symbol file.
We heard your feedback around symbol uploading for main applications and stand-alone libraries. And with the latest Crashlytics Gradle plugin, specifying the stripped library directory is no longer necessary so you can get quickly set up with minimal error. We’ve also allowed the unstripped path to point to disparate directories, allowing symbol upload for binaries that are compiled outside of the main application.
We’ve improved grouping for Unity crashes to help you more quickly debug and identify the exact cause of a crash. Our analysis backend now has a more robust set of Unity heuristics, resulting in much better issue fidelity and a more intuitive stack trace visual treatment. No longer will issues highlight a system frame when an application frame is the source of the problem.
Revised Unity Grouping in Crashlytics Console
We’ve enabled automatic capture of various hardware attributes and game-specific values to help solve unique issues related to the model of GPU and screen resolution for example, so you no longer have to capture these yourself and use up valuable key-value pairs.
Unity metadata in Crashlytics console
We hope these improvements help make identifying crashes much easier, and we will continue to improve the games experience by focusing on improving Unity IL2CPP support - support that includes capturing Unity Engine and native extension crashes. Let Crashlytics handle crashes for all of the components that your game depends on, because sometimes, the crash is not your game's fault. There is much more on the horizon, stay tuned!
In the meantime to get started, head to our NDK and Unity onboarding pages. We're excited to help you through your game development journey and can’t wait to hear what you think!
Since Firebase first released an iOS SDK, CocoaPods has been the preferred way to add Firebase to your iOS projects. CocoaPods has served the iOS community well and has made adding libraries and frameworks as easy as adding their package name to your project's Podfile file and running pod install.
Podfile
pod install
In recent years, Swift Package Manager has grown in popularity thanks to being officially supported by Apple, and its tight integration with Xcode. The 2020 iOS Developer Community Survey shows that more than 41% of app developers use Swift Package Manager in their business apps. For hobby/personal apps, that number is even higher at > 56% of developers using Swift Package Manager in their projects.
Adding support for Swift Package Manager has been one of the most requested features in our issue tracker:
Firebase shipped initial (beta) support for Swift Package Manager in August 2020 with Firebase 6.31.0 for a partial set of Firebase products.
Today, we are excited to announce that as of Firebase 8.6.0 for iOS, Firebase fully supports Swift Package Manager. This means you can now add Firebase to your iOS project without leaving Xcode. Gone are the days of having to maintain a working Ruby installation, or having to remember the correct command line arguments just to be able to add a Swift library to your iOS project.
Adding Firebase to your iOS project is easier than ever before with Xcode 12.5:
Adding support for Swift Package Manager was a multi-year project that not only required us to refactor our directory structure and build options to conform to SwiftPM's requirements - we also worked closely with the SwiftPM community to resolve integration issues with binary libraries, resource support, and - last but not least - unit testing support.
Performance Monitoring was the last Firebase product that was missing support for Swift Package Manager, and just a few days ago, the Performance Monitoring team completed their work to get ready for SwiftPM. This involved substantial investment in migrating from Protobuf to nanopb, a refactoring that reduced the size of the SDK by more than 30%.
We know that many of you have been looking forward to being able to migrate to a SwiftPM-only project setup, and we're excited to be able to say that using Swift Package Manager is now the preferred way to add Firebase to your iOS project.
We're working on updating the documentation, setup flows, and quickstart apps to reflect this change.
Come visit us on our GitHub discussion board and issue tracker, and let us know what you think, or if you have any questions about migrating from CocoaPods to Swift Package Manager.
You've asked for it, and now it's here! We're excited to announce that version 9 of the Firebase SDK is now generally available. This new version adopts a module first format that is optimized for elimination of unused code. The result is a potential significant reduction of Firebase library code in JavaScript bundles, up to 80% in some scenarios.
As of today running npm install firebase will download the version 9 library. This new API is a major release and introduces several breaking changes. Upgrading to the new version can be done all at once or at your own pace with our compatibility library (more on that below). This post covers everything you need to know to get started. Check out our upgrade guide as well as our guide to using the new SDK with module bundlers for detailed guidance.
npm install firebase
API changes for reduced size
Version 9 introduces a functional approach. In previous versions the API was organized into a traditional object-oriented structure. Using individual functions instead of structured objects allows JavaScript module bundlers such as webpack and Rollup to remove any unused code from the library. This is a concept known as tree shaking.
import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged, getRedirectResult } from 'firebase/auth'; const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(); onAuthStateChanged(auth, user => { console.log(user); });
While this library organization is new, we have kept in place many familiar API concepts.
// 9.0.0 import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; const firebaseApp = initializeApp({ /* config */ }); const auth = getAuth(); onAuthStateChanged(auth, user => { console.log(user); }); // 8.8.1 import firebase from 'firebase/app'; import 'firebase/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = firebaseApp.auth(); auth.onAuthStateChanged(user => { console.log(user); });
The sample above compares the same functionality, has the same amount of lines of code, and a similar API. The version 9 code however is 72% smaller than the version 8 example.
Keep in mind that while our functional approach is beneficial for tree shaking, this does not require you to write your code functionally. This new format provides an "import only what you need" approach. You can still structure your code in the ways that work best for you and your team.
import { getApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; class AuthService { constructor(firebaseApp) { this.auth = getAuth(firebaseApp); } waitForUser(callback) { onAuthStateChanged(this.auth, user => { if(user != null) { callback(user) } }); } } const authService = new AuthService(getApp()) authService.waitForUser(user => { });
import { getApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; function waitForUser(auth, callback) { onAuthStateChanged(auth, user => { if(user != null) { callback(user) } }); } const auth = getAuth(getApp()); waitForUser(auth, user => { });
The samples above follow different structures. However, they have nearly the same bundle size. This is because they import the same pieces of functionality from the Firebase SDK.
A compatibility library for an easier upgrade
We understand that having to update code can be a lot of work. While your end users will experience real benefits in terms of bundle size and therefore page load performance, we want to make sure you can upgrade with minimal friction.
To simplify the upgrade process we have provided a compatibility library that ships with the version 9 npm package and is also available via a CDN script. To use the compatibility library via npm, you only need to update the import path.
import { initializeApp } from 'firebase/compat/app'; import 'firebase/compat/auth; import { onAuthStateChanged } from 'firebase/auth'; const firebaseApp = firebase.initializeApp({ /* config */ }); const auth = firebaseApp.auth(); onAuthStateChanged(auth, user => { console.log(user); });
This library mirrors the version 8 API while using the version 9 library under-the-hood. It does not work with tree shaking, but it allows you to use the old and new APIs together. We refer to this as interop-mode.
Once your code is fully upgraded, you can remove the compatibility library and begin to see any potential tree shaking benefits.
Introducing Firestore Lite
We're also excited to announce our newest library, Firestore Lite. Firestore Lite provides a REST based API for Firestore at a fraction of the bundle size. The library does not have support for realtime reads or any offline abilities. It is ideal for users who use Firestore for one-time reads.
import { initializeApp } from 'firebase/app'; import { getFirestore, collection, getDocs } from 'firebase/firestore/lite'; const firebaseApp = initializeApp({ /* config */ }); const db = getFirestore(); const snapshot = await getDocs(collection('cities'));
Another benefit of Firestore Lite is that it can be used with the fully featured Firestore package. Some pages may only require single reads whereas some may need realtime streams. You have the option of using either (or both) in your web app where needed.
Moving away from the browser's global window object
Another significant development in the new SDK is the move towards JavaScript modules (ESM) and away from the browser's global window object.
window
Historically libraries have been loaded and managed via a namespace on the window, such as window.firebase. This technique does not allow for tree shaking and lacks other benefits of the JavaScript module system.
window.firebase
This release prioritizes usage of Firebase via JavaScript modules. We still provide support for the window via a CDN script for the compatibility library. However, we only recommend using it as a path to upgrading to the module based SDK.
Get started today
We are really excited about the new JavaScript SDK and we want to hear from you as well. We'll be watching and responding to our GitHub discussion board for any questions or comments. If you've seen any size reductions in your codebase and want to share, let us know!
The Firestore Emulator Requests Monitor allows you to see requests to your local Firestore Emulator in real-time, and drill down to the details of each request, such as method, path, and Firebase Security Rules evaluation. You can access the Requests Monitor right now from the Emulator UI if you have the latest Firebase CLI running. (If not, it's never too late to upgrade!)
Requests Monitor helps you understand your request traffic in detail, and puts Firebase Security Rules front and center (just like security should be in your production app). Ever wonder what collections are pulled in for the amazing pizza tracker feature in your app? Forgot about how that cute button is backed by 400 lines of code changes Firestore? Worried about changes to security rules breaking production apps? The Requests Monitor has answers to all of these questions, plus more!
First, start the Emulator Suite, then navigate to the Firestore tab in the Emulator UI and you'll be greeted with two views: the default "Data" view is the familiar data viewer and editor you know and love, and the "Requests" view is just a click away.
Each client request to the Firestore Emulator will be added to the table as a new row. For example, if you connect your app to the Firestore Emulator and create a new document, it will show as a CREATE request on the table in real time. This works regardless of which platform your app is on -- be it Android, iOS, web, or anything else. And if you ever forget to open this page before you make those requests, don't worry -- we've got you covered. The last few requests will be kept for you to review when you navigate to the Requests page.
CREATE
The Requests View is a great help in developing security rules. A checkmark indicates if the request has been allowed by your security rules; denials and errors are also displayed. If you follow best practices and keep your rules locked down as much as possible, you'll certainly see some denials when you develop new features, and those are the perfect opportunity to learn! To take the guesswork out of updating security rules, just click on any request to see the evaluation details view.
On this page, you'll see your current local security rules on the left, and some information about the specific request on the right. Statements that allow, deny, or error will be highlighted. You may also run into situations where the request is not yet covered by any of the allow statements and is thus denied by default. Ever wonder why a request is denied where it should be allowed, or the reverse? The panel on the right can help. You can see the existing resource, the would-be version of the document (i.e. request.resource) and other important fields in the request. If your goal is to modify the security rules to align with changes to your app, you can also use those fields as inspiration for new conditions that your rules should gate on.
resource
request.resource
While we're at it, you'll notice the security rules on the evaluation details page are not modifiable -- that's because they are snapshots at the time when the request happened. To make rules changes, just directly modify the firebase.rules file with your favorite editor or IDE and the Firebase CLI will automatically apply the changes to the Firestore Emulator. And if you make another request, it will show up in the table view as a different row with new rules and results. Sometimes, it may be helpful to compare the old and new rules and see differences in how they were evaluated.
firebase.rules
For those of you who are familiar with the Security Rules Playground in Firebase Console, you may miss the simulated requests feature here. But in the emulator world, there's no need to guess what a request should look like -- you can just simply make that request from your app using the Firestore SDK in your favorite programming language. The Request Monitor always shows you faithfully how that request is represented in Security Rules and the actual decision of your rules. Any client request is fair game -- even lists and queries that are hard to simulate in production. We think you will eventually get used to it and love this new interactive development workflow as much as we do.
While you enjoy the new Requests Monitor, just keep in mind that only client requests are shown in the table. Admin requests bypass any security rules and therefore don't appear in the list. Similarly, if your rules depend on other documents in the Firestore (e.g. get(...) or exists(...)), only the main request is shown but not the dependent fetches, even though those dependent fetches count towards your quotas and billing in production. Just remember emulated benchmarks are not an indicator of production in terms of performance or cost estimation.
get(...)
exists(...)
We've already heard some developers asking if this feature will also be available in Firebase Console. While we cannot say for sure, recording production requests will certainly create a huge challenge to your app's Firestore performance and security. Aaaand, well, you know, production is not the best place to test out changes, especially security-related changes. We recommend developing and testing locally before rolling out to production, and the Firebase Emulator Suite is always seeking ways to help.
With the Firestore Emulator and Requests Monitor, you can see your prototyping path more clearly. In fact, you have a better view into unit and integration testing as well: just make sure to keep the Monitor open and run your tests against the same (emulated) Project ID that your app connects to. You only need to deploy when you feel comfortable with your changes.
Feel free to play around with the Firestore Emulator Requests Monitor, and let us know what you think!
Recently we shared the story of how CrazyLabs, a casual and hypercasual publisher, used Firebase Remote Config to optimize their portfolio of apps at scale. While CrazyLabs had success automating their testing with the Remote Config API, Remote Config can also be a great tool for achieving fast results that have a direct impact on revenue.
Vinwap is an indie developer who helps users personalize their Android devices with “live” wallpaper apps, including Glitter Live Wallpaper Glitzy and 4D Parallax Wallpaper. They use AdMob to monetize their apps, and wanted to see if increasing their use of banner ads would help to increase revenue without alienating their existing users.
Check out our latest case study to see how Vinwap was able to increase revenue by 30% in only six days, and why Wojciech Stefanski, the founder of Vinwap, called Firebase “the go to analysis tool when introducing any new changes.”