tag:blogger.com,1999:blog-41915487402201307492024-01-01T22:41:43.787-08:00The Firebase Blogewoodhttp://www.blogger.com/profile/12341551220176883769noreply@blogger.comBlogger412125tag:blogger.com,1999:blog-4191548740220130749.post-50090889858489607542022-03-18T08:58:00.001-07:002022-03-18T12:45:57.517-07:00#FirebaserFriday: Frank van Puffelen<meta name="https://blogger.googleusercontent.com/img/a/AVvXsEgEjSVOU6TxfHa5gSCZZPpmDBAKk1ZPGfkVtmIEeAlhXV35ECaAL5UhAo53mhlqy2OBq07h8wxK5IyKqlFvwJ0muzkjj-DRMN_EeJbnF5dxCtmu4TrZ9fsm5gF0J8uEP1GRtmd-49FSX6_iFn3oAaFxkdJzHVHb1bhHRJYYey3OqRCl0aVOdi42RcCP7A">
<img style="display:none" src="https://blogger.googleusercontent.com/img/a/AVvXsEgEjSVOU6TxfHa5gSCZZPpmDBAKk1ZPGfkVtmIEeAlhXV35ECaAL5UhAo53mhlqy2OBq07h8wxK5IyKqlFvwJ0muzkjj-DRMN_EeJbnF5dxCtmu4TrZ9fsm5gF0J8uEP1GRtmd-49FSX6_iFn3oAaFxkdJzHVHb1bhHRJYYey3OqRCl0aVOdi42RcCP7A">
<figure class="profile">
<div class="profile-picture">
<img src="https://blogger.googleusercontent.com/img/a/AVvXsEji2-cB3dglWYcNyaDn6pN-QXCig12a1KvRwzLvsKwwJRtPaYzT_awfQe1lu6-wjCS5gwHOP4HfyK43IePwbls59s4s1p8xy-YXmf2OFnV8ktso_26GgtKpUfVpFJqbd0ZnJ6lPE2VtH8s4dctn1peqGnIo7aaoZlHWIBk-E8sPj2l5b-7vYRWdZw7zxA"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div>Paulette McCroskey</div>
</strong>
<em>Social Media Manager, Advanced Systems Group, LLC</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgEjSVOU6TxfHa5gSCZZPpmDBAKk1ZPGfkVtmIEeAlhXV35ECaAL5UhAo53mhlqy2OBq07h8wxK5IyKqlFvwJ0muzkjj-DRMN_EeJbnF5dxCtmu4TrZ9fsm5gF0J8uEP1GRtmd-49FSX6_iFn3oAaFxkdJzHVHb1bhHRJYYey3OqRCl0aVOdi42RcCP7A" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of Firebaser Friday blog header" border="0" data-original-height="900" data-original-width="1600" src="https://blogger.googleusercontent.com/img/a/AVvXsEgEjSVOU6TxfHa5gSCZZPpmDBAKk1ZPGfkVtmIEeAlhXV35ECaAL5UhAo53mhlqy2OBq07h8wxK5IyKqlFvwJ0muzkjj-DRMN_EeJbnF5dxCtmu4TrZ9fsm5gF0J8uEP1GRtmd-49FSX6_iFn3oAaFxkdJzHVHb1bhHRJYYey3OqRCl0aVOdi42RcCP7A"/></a></div>
<h2>Welcome to #FirebaserFriday!</h2>
<p>
Join us for the monthly mini-profiles on Firebase team members, aka “Firebasers”, from all around the world! Learn about their backgrounds, how they got started with Firebase, what Firebase products they work on, their favorite ways to de-stress, advice, and more.
</p>
<p>
For our first feature, we’re happy to introduce you to a long standing member of the Firebase community. You may know his work from Firebase Release Notes, one of his talks at Google events, or used one of his many community responses from Stack Overflow. And now, we give you <strong>puf</strong>!
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh9CaXsIDQ9ZlBfd9BkTJW3yIE1lvFf8X-wd1Ufi3Z3Azzr6--fu0GkjUUuVv4vIcIpGulm7CcqzSKjIXBkr9uHwS3D3aIL6dl6AQsn74XHQkAayRStj1RKosW5HOX1jEfsD-0x4FxNCW-Q5qnOtee6LxhU4zDVC4IqhgFueXs72Py7fUIcXbKOZBzU6g" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="gif of Firebaser puf" border="0" data-original-height="1200" data-original-width="1200" src="https://blogger.googleusercontent.com/img/a/AVvXsEh9CaXsIDQ9ZlBfd9BkTJW3yIE1lvFf8X-wd1Ufi3Z3Azzr6--fu0GkjUUuVv4vIcIpGulm7CcqzSKjIXBkr9uHwS3D3aIL6dl6AQsn74XHQkAayRStj1RKosW5HOX1jEfsD-0x4FxNCW-Q5qnOtee6LxhU4zDVC4IqhgFueXs72Py7fUIcXbKOZBzU6g"/></a></div>
<h3><strong>How did you get started with Firebase?</strong></h3>
<p>
I was in the habit of answering questions on <a href="https://stackoverflow.com/users/209103/frank-van-puffelen?tab=answers">Stack Overflow</a> to learn about interesting new technologies, when questions about Firebase started showing up. My answers got noticed, and that led to me becoming a member of the Firebase team at Google. And 7 years later, answering questions about Firebase on Stack Overflow is still one of my favorite things to do each day!
</p>
<h3><strong>What are you working on right now?</strong></h3>
<p>
I just gave a talk at Flutter Vikings about <a href="https://youtu.be/50qRPvg0CJg?t=25204s">synchronizing game state in a Flutter app</a>, and, as part of the Flutter Puzzle Hack, about <a href="https://youtu.be/kWjJ0aUq5L0?t=533">adding Firebase to your Flutter app</a>. I'm also working with the Flutter GDEs to get more/better Flutter answers on Stack Overflow. Between that, answering questions on Stack Overflow, and the monthly <a href="https://www.youtube.com/playlist?list=PLl-K7zZEsYLm9G2M1W5ztrDvMv-CiFzLM">Firebase Release Notes</a> video, I keep busy. :)
</p>
<h3><strong>Do you have a nickname? How did you get it?</strong></h3>
<p>
Not sure if it counts as a nickname, but I am known as puf. While I respond to both Frank and puf equally, I'm usually the only puf in the room. I got the nickname in my teens, as I was really tired of all the variations of my last name, and I've been known as “puf” to most people since then.
</p>
<h3><strong>What are you reading right now?</strong></h3>
<p>
I <a href="https://www.goodreads.com/user/show/24654655-frank-van-puffelen">read a lot</a>. I just finished <a href="https://www.goodreads.com/book/show/51625073-the-lincoln-conspiracy">The Lincoln Conspiracy</a> and am halfway through <a href="https://www.goodreads.com/book/show/30133224-carve-the-mark">Carve the Mark</a> and <a href="https://www.goodreads.com/book/show/6011852-the-brothers-karamazov">The Brothers Karamazov</a>.
</p>
<h3><strong>Where can we find your work?</strong></h3>
<p>
You can find me on Twitter <a href="https://twitter.com/puf">here</a>.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-9700864381910790932022-03-09T08:58:00.000-08:002022-03-09T08:58:48.414-08:00How Firebase Performance Monitoring optimized app startup time<meta name="https://blogger.googleusercontent.com/img/a/AVvXsEhYA6fnjrSWWZv4HHo3ciW-LYb5Tg6JA4yvdlyGbVZpXqWyY_EXxJZEHKQGdnmY2njYhbQ41M27pIJ7L3HVCZAyx3EFHXBr3EoIngrQf5yhK9lDwvZDamaiAoU3ZxwDEZPMf3KsVQxVLWUyFqAMOHTKpn_siAeSbhfvukXfnBU1CLNhbAkxgDe8uWD5IQ">
<img style="display:none" src="https://blogger.googleusercontent.com/img/a/AVvXsEhYA6fnjrSWWZv4HHo3ciW-LYb5Tg6JA4yvdlyGbVZpXqWyY_EXxJZEHKQGdnmY2njYhbQ41M27pIJ7L3HVCZAyx3EFHXBr3EoIngrQf5yhK9lDwvZDamaiAoU3ZxwDEZPMf3KsVQxVLWUyFqAMOHTKpn_siAeSbhfvukXfnBU1CLNhbAkxgDe8uWD5IQ">
<figure class="profile">
<div class="profile-picture">
<img src="https://blogger.googleusercontent.com/img/a/AVvXsEjK3tNWtBw8JtaRZUabPmn3tFW1t_mfKK19S3X7yPWcm1M7bkAr6LXmRETBNJ0h09HvjrUIaNPhaw971HXagOSK3yPy-vQN3HfardP-qarShWTbZVEgr3tboDyFzuxAx7uaMycrw2WGgc8FyoaOdokrlWGpFpTomSYWKifiN78gEOciuBlm0e_WPVBwYA"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div>Viswanathan Munisamy</div>
</strong>
<em>Software Engineer</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjDu-3bTWrkraOXj6beIQWeIcqCpeFmts4wnyVXmXg2RkqS2ct1AgIKEG_gGuAu-dylbx2In7PIyAKWLMsH-TBIQFOMqNGYeoPSz4zglKQ6NYvwxytbkvh33dilNwAhmLdzbww_yFQf3ZANIw6oXPkvz_anwIWar76-Ql14_HAeqD5A4xbJwxEmzpyx2g" style="display: block; padding: 1em 0; text-align: center; "><img alt="blog header image" border="0" data-original-height="1258" data-original-width="4213" src="https://blogger.googleusercontent.com/img/a/AVvXsEjDu-3bTWrkraOXj6beIQWeIcqCpeFmts4wnyVXmXg2RkqS2ct1AgIKEG_gGuAu-dylbx2In7PIyAKWLMsH-TBIQFOMqNGYeoPSz4zglKQ6NYvwxytbkvh33dilNwAhmLdzbww_yFQf3ZANIw6oXPkvz_anwIWar76-Ql14_HAeqD5A4xbJwxEmzpyx2g"/></a></div>
<p>
Mobile users expect their apps to be fast and responsive, and apps with a slow startup time, especially during <a href="https://developer.android.com/topic/performance/vitals/launch-time#cold">coldstart</a>, can leave them feeling frustrated. <a href="https://firebase.google.com/docs/perf-mon?authuser=0">Firebase Performance Monitoring</a> is a tool that helps you gain insight about various app quality signals, including startup time of your application. This article gives a deep dive into the Firebase Performance Monitoring tool and its impact during an Android application’s cold start.
</p>
<h2>Library impact at startup</h2>
<p>
Modern Android applications perform multiple operations until the application becomes responsive to the user. “Startup time” of an application measures the time between when an application icon is tapped on the device screen, to when the application is responsive. Code executing during startup time includes the application's code, along with code from dependencies that are involved in app startup. Any code that executes until the first frame is drawn is reflected in the <a href="https://developer.android.com/topic/performance/vitals/launch-time#time-initial">time to initial display</a> metric.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg_YzaekA6XbfUnLHPwsSSmlcddI88SM5JwAflsf8Xwf-xWKRNg7c0kmjNp686DYk0-0jzElGQctsI2cR-oQnDS-lV92NubgNnP2gWXgaJa6TMMpJAEVYWiGJ3WKiHdee3sZDj487w495TZIIhD9-3MngZC_uw2MKsrg_iMYkeyw9QhNkrGRdHgswwEcQ" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image showing the App and SDK startup time" border="0" data-original-height="278" data-original-width="624" src="https://blogger.googleusercontent.com/img/a/AVvXsEg_YzaekA6XbfUnLHPwsSSmlcddI88SM5JwAflsf8Xwf-xWKRNg7c0kmjNp686DYk0-0jzElGQctsI2cR-oQnDS-lV92NubgNnP2gWXgaJa6TMMpJAEVYWiGJ3WKiHdee3sZDj487w495TZIIhD9-3MngZC_uw2MKsrg_iMYkeyw9QhNkrGRdHgswwEcQ"/></a></div>
<p>
Many libraries do not need to get initialized during the application startup phase. Some libraries, like Firebase Performance Monitoring, provide value by initializing during the startup phase. It is this early initialization that enables measurement of app start, CPU/Memory impact during early phases of startup, and performance of network requests during application startup. But, this could lead to an increase in the startup time of the application.
</p>
<p>
You can measure the impact of a library during your app’s startup by creating 2 versions of your app (<strong>with </strong>and<strong> w/o the library) </strong>and measuring the “time between <strong><em>Application launch</em></strong> to <strong><em>Activity firstFrameDrawn</em>”</strong> in both to compare<strong>.</strong>
</p>
<h2>Firebase Performance Monitoring at startup</h2>
<p>
Firebase Performance Monitoring performs the following tasks during an application cold start:
</p>
<ul>
<li>Registers dependencies
<ul>
<li>Configuration management: Controls measuring performance metrics on a percentage of devices by looking at locally cached configurations
<li>Firebase Installations: Installation service for each Firebase installed device
</li>
</ul>
<li>Initializes the performance library
<li>Tracks the startup time of the application
<li>Measures detailed system metrics (CPU/Memory) for a fraction of the cold starts (See <a href="https://firebase.google.com/docs/perf-mon/console?platform=android#sessions">sessions</a>).
</li>
</ul>
<p>
Firebase Performance Monitoring does all these without developers needing to add any lines of code to their application.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh0GEPyH5y0XaNmxv1RD5z6vBeXS0hkp0ZtQUH5GFU_MnLxxa6ZSY0polpalOLwQ6HdAVe_eQn9nwggr8YRNXcVhfo9BYUrfK1B3pivQFiXj2F-_Zk464Q_AaunkcPrCnClx0BUwxXWURJJNa_1hP455TFb10Q8ct2tVQdIuIypK8aErGqK6eXXy064JA" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image showing the timeline of performance monitoring app startup time optimization" border="0" data-original-height="344" data-original-width="624" src="https://blogger.googleusercontent.com/img/a/AVvXsEh0GEPyH5y0XaNmxv1RD5z6vBeXS0hkp0ZtQUH5GFU_MnLxxa6ZSY0polpalOLwQ6HdAVe_eQn9nwggr8YRNXcVhfo9BYUrfK1B3pivQFiXj2F-_Zk464Q_AaunkcPrCnClx0BUwxXWURJJNa_1hP455TFb10Q8ct2tVQdIuIypK8aErGqK6eXXy064JA"/></a></div>
<h2>Performance Monitoring app startup time optimization</h2>
<p>
There are <a href="https://developer.android.com/topic/performance/tracing#guides">many tools</a> available to profile the performance of an application. We used the following tools for measuring the startup time and analyzing the impact of every single method in our library during application cold start.
</p>
<p>
<a href="https://developer.android.com/studio/profile/macrobenchmark">Macrobenchmark</a> is a recent tool launched at Google I/O '21 to measure the startup and runtime performance of your application on physical devices. We used this tool to measure the overall time taken by an application during a cold start.
</p>
<p>
<a href="https://developer.android.com/studio/profile/benchmark#method_tracing">Method tracing</a> enables understanding all the classes/methods that were involved in the runtime of an application. This lists down the different methods that get executed at runtime and the duration each method takes for execution. Due to the <a href="https://developer.android.com/studio/profile/benchmark#method_tracing">overhead of method tracing</a>, the duration of methods as specified in the trace file is bloated. Nonetheless, this duration can be used as a guiding metric to understand the impact of a method.
</p>
<p>
Using the method tracing APIs, we identified multiple opportunities within the application’s lifecycle events to reduce the impact of the library during application startup, including:
</p>
<ul>
<li>Content Provider
<li>Activity Create
<li>Activity onResume
</li>
</ul>
<p>
We optimized the library in all these phases. Some key optimizations include:
</p>
<ul>
<li>In the content provider phase, we moved away from eager initialization to <a href="https://github.com/firebase/firebase-android-sdk/pull/2518">lazy initialization</a> creating components when needed. Eg: dependency initialization.
<li>In the phases of activity onCreate() and onResume(), we moved many of the non-essential operations from main thread to run on background thread allowing the main thread to focus on the applications’ needs (<a href="https://github.com/firebase/firebase-android-sdk/pull/3044">#1</a>, <a href="https://github.com/firebase/firebase-android-sdk/pull/3008">#2</a>)
<li><a href="https://github.com/firebase/firebase-android-sdk/pull/3011">Delayed initialization</a> of certain non-urgent firebase performance components to a later time after the application has performed its startup operations. Eg: Event dispatch service
<li><a href="https://github.com/firebase/firebase-android-sdk/pull/2968">Delayed fetching</a> of remote configurations Eg. Firebase Remote Configuration
</li>
</ul>
<h2>Impact of Firebase Performance Monitoring</h2>
<p>
To benchmark the impact of Firebase Performance Monitoring, we built a simple Android application. Benchmarking performance depends on various factors. To make this measurement close to user needs, we measured the startup time with the following factors.
</p>
<ul>
<li>Simple empty android application
<li>Samsung 2019 model device
<li>Android API Level of the device - API level 29
<li>Macrobenchmark version: 1.1.0-alpha09 (Compilation mode: <a href="https://developer.android.com/reference/kotlin/androidx/benchmark/macro/CompilationMode.Full">Full</a>)
<li>Firebase performance library version - <a href="https://firebase.google.com/support/release-notes/android#performance_v20-0-4">20.0.4</a>
</li>
</ul>
<p>
We ran the application with and without Firebase performance library to understand the startup time impact caused by the library. We used macrobenchmark to measure the duration of the startup time.
</p>
<p>
For an empty application with the above ground conditions, the table below captures the impact of the application startup before and after the optimizations.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgBmKaf98IQyFDQ2LQ81MsM1SUEMVyrku9-piTQQb0elEDZofgVSewWarww3sqv7lvKvUuZg2IaOzEW4ortnujoz5HLNDExWXXDJAIorUYcyL3RfjHm9qwrVykZ2jeo9hg0nh2Xxz3mTYUKNU3CI88qI2vEB-SWvoJm9Z9ZxleaBFlHy4IZVs21ciSlew" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image showing a chart capturing the impact of the application startup before and after optimizations" border="0" data-original-height="404" data-original-width="1326" src="https://blogger.googleusercontent.com/img/a/AVvXsEgBmKaf98IQyFDQ2LQ81MsM1SUEMVyrku9-piTQQb0elEDZofgVSewWarww3sqv7lvKvUuZg2IaOzEW4ortnujoz5HLNDExWXXDJAIorUYcyL3RfjHm9qwrVykZ2jeo9hg0nh2Xxz3mTYUKNU3CI88qI2vEB-SWvoJm9Z9ZxleaBFlHy4IZVs21ciSlew"/></a></div>
<p>
With all the above changes, we have been able to reduce the impact of the library during startup time by <strong>more than 35%</strong>.
</p>
<h2>What’s next?</h2>
<p>
Application startup time improvement is a moving target for all developers. Though device hardware has been dramatically improving in recent years, the challenge of improved startup time performance continues to push barriers. We are continuously investing in reducing the startup time impact.
</p>
<p>
Update your Firebase Performance Monitoring SDK to the <a href="https://firebase.google.com/support/release-notes/android#latest_sdk_versions">recent version</a> to get these recent improvements on startup time, <a href="https://firebase.google.com/docs/perf-mon/troubleshooting?platform=android#faq-real-time-data">realtime metrics</a> and <a href="https://firebase.google.com/docs/perf-mon/alerts">alerts</a>.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-21864962085953913032022-02-15T08:58:00.000-08:002022-02-15T08:58:26.901-08:00Using Machine Learning to optimize mobile game experiences<meta name="https://blogger.googleusercontent.com/img/a/AVvXsEicO9oO6B1gmS781YuLg7rk_BkZvWvtBU5FgtlKO8n4RCX0Ct8JhBxa5AqQZV2eCu_z9pWnpEk5UPQ18bHYMXFvAuxu_gfY6N4iT5ec16brXDYOzXU0VHCAfYd-p5LFnc_QqWtpQR1-xG57HzWVMO4zYfGpi4JrrdjwasTO2_j7ygesLnKwO3uqCAfVDg">
<img style="display:none" src="https://blogger.googleusercontent.com/img/a/AVvXsEicO9oO6B1gmS781YuLg7rk_BkZvWvtBU5FgtlKO8n4RCX0Ct8JhBxa5AqQZV2eCu_z9pWnpEk5UPQ18bHYMXFvAuxu_gfY6N4iT5ec16brXDYOzXU0VHCAfYd-p5LFnc_QqWtpQR1-xG57HzWVMO4zYfGpi4JrrdjwasTO2_j7ygesLnKwO3uqCAfVDg">
<figure class="profile">
<div class="profile-picture">
<img src="https://blogger.googleusercontent.com/img/a/AVvXsEjB1Yvw2pFfyQEeME_-nsY8RXsCvkuUGPQeOc5BDGd6PzSCFMGf5g1w3b_ljiXS1j7PSgtvyFCTUC8LweIYlyR2lmUb1rFxqKsJiAKaLJfkAAy3O-ImGDMXLQabQssF8yDuxTo9Cn9pD3i9WR4i4i_VouCKLV2fSIwxbfw5ljPqGHAD4E3IhAtmEAr90A"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div>Sachin Kotwani</div>
</strong>
<em>Senior Product Manager</em>
</figcaption>
</figure>
<figure class="profile">
<div class="profile-picture">
<img src="https://blogger.googleusercontent.com/img/a/AVvXsEiDWc1lWjVw-8OupSkEQz4EvFmln4CAwAmTGtZV75qCBu_XOWN8UI33dIn7bEWEnHGwjgEPu3wZsDq_Ctdk6LlvayphGzXdOlBr_EVd28gXzVA0xyqdGC1AN3pc2KK8MFjdTVhFK15QBR1ND7cq76bys5XVN9ENM_QL3AC1ZCwnE_PlAfDz6mZwAC_xQQ"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div>Elvis Sun</div>
</strong>
<em>Software Engineer</em>
</figcaption>
</figure>
<p>
Mobile app and game developers can use on-device machine learning in their apps to increase user engagement and grow revenue. We worked with game developer HalfBrick to train and implement a custom model that personalized the user's in-game experience based on the player's skill level and session details, resulting in increased interactions with a rewarded video ad unit by 36%. In this blog post we'll walk through how HalfBrick implemented this functionality and share a <a href="https://firebase.google.com/codelabs/iap-optimization#0">codelab</a> for you to try it yourself.
</p>
<p>
<strong>Background</strong>
</p>
<p>
Every end-user or gamer is different, and personalizing an app purely based on hard-coded logic can quickly become complex and hard to scale. However, taking all relevant signals into account, game developers can train a Machine Learning model to create a personalized experience for each user. Once trained, they can “ask” the model to give the best recommendations for a particular user given a set of inputs (e.g. “Which item from the catalog should I offer to a user that has reached skill level ‘pro’, is on level 5, and has 1 life left?")
</p>
<p>
Custom ML models can be architected, tuned, and trained based on the inputs that you think are relevant to your decision, making the implementation specific to your use case and customers. If you are looking for a simpler personalization solution that doesn’t require you to train your own model and where the answer is unlikely to change multiple times per session (e.g. "What is the right frequency to offer a rewarded video to each user?") we recommend using Firebase Remote Config’s <a href="https://firebase.google.com/docs/remote-config/personalization">personalization</a> feature.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEicO9oO6B1gmS781YuLg7rk_BkZvWvtBU5FgtlKO8n4RCX0Ct8JhBxa5AqQZV2eCu_z9pWnpEk5UPQ18bHYMXFvAuxu_gfY6N4iT5ec16brXDYOzXU0VHCAfYd-p5LFnc_QqWtpQR1-xG57HzWVMO4zYfGpi4JrrdjwasTO2_j7ygesLnKwO3uqCAfVDg" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image showing game from Halfbrick" border="0" data-original-height="256" data-original-width="512" src="https://blogger.googleusercontent.com/img/a/AVvXsEicO9oO6B1gmS781YuLg7rk_BkZvWvtBU5FgtlKO8n4RCX0Ct8JhBxa5AqQZV2eCu_z9pWnpEk5UPQ18bHYMXFvAuxu_gfY6N4iT5ec16brXDYOzXU0VHCAfYd-p5LFnc_QqWtpQR1-xG57HzWVMO4zYfGpi4JrrdjwasTO2_j7ygesLnKwO3uqCAfVDg"/></a></div>
<p>
We recently worked with game developer HalfBrick on optimizing player rewards within one of their most popular games, with over 500M downloads, Jetpack Joyride. In-between levels, players are presented with an option to obtain a digital good by watching a rewarded video ad. Our objective was to increase the conversion rate for this particular interaction. Before the study, the digital good offered in return for watching the ad was always selected at random. Using a custom ML model, we were able to personalize which reward to offer using inputs such as the gamer’s skill level, and information about the current session (e.g. why they died in the last round, what powerups they selected), and increased conversions by 36% in just our first iteration of the experiment. Once trained, the model runs fully on-device, so it doesn’t require network requests to a cloud service and there are no per-inference costs.
</p>
<p>
<strong>Solution</strong>
</p>
<p>
ML workflows largely anchor themselves on to the following components: A problem to solve, data to train the model, training of the model, model deployment, and client-side implementation. We have described the problem above, and will now cover the rest of the steps. You can also follow along with more detailed implementation steps in the <a href="https://firebase.google.com/codelabs/iap-optimization">codelab</a>.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjemP3gs_Ij9V-xL1_TqpUdlHSc8lgyW20jraRAFlVazWgiT1zFNqjXJ_05Hm5SJM7bsADSEwgrga-pnZpHM247GUrsMBV9g8RwIplCCUVwuLFWTu_tt2F1wP8fH0OvwGFLtOA9O-q_VUkZwbjGP70sYssRAmv5hw3KS4BJMLGIaGeOuU9DMyaY0AHn9Q" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image showing how to collect the data necessary to train the model" border="0" data-original-height="77" data-original-width="512" src="https://blogger.googleusercontent.com/img/a/AVvXsEjemP3gs_Ij9V-xL1_TqpUdlHSc8lgyW20jraRAFlVazWgiT1zFNqjXJ_05Hm5SJM7bsADSEwgrga-pnZpHM247GUrsMBV9g8RwIplCCUVwuLFWTu_tt2F1wP8fH0OvwGFLtOA9O-q_VUkZwbjGP70sYssRAmv5hw3KS4BJMLGIaGeOuU9DMyaY0AHn9Q"/></a></div>
<p>
<strong>Collect the data necessary to train the model</strong>
</p>
<p>
HalfBrick collected 129 different signals to train the model. These were of different types, such as event timestamp, user skill levels, information about recent sessions, and other information about the user's gameplay style. This is where intuition around which factors could influence the outcome are very helpful (e.g. a user’s skill level, point balance, or choice of avatar may be useful when predicting which powerups they’d prefer).
</p>
<p>
We can collect training data easily by sending events to <a href="https://firebase.google.com/products/analytics">Google Analytics for Firebase</a> and then exporting them to <a href="https://cloud.google.com/bigquery">BigQuery</a>. BigQuery is Google’s fully-managed, serverless data warehouse that enables scalable analysis over petabytes of data. In our scenario, it makes it easy to summarize and transform the data to get it ready for model training, as well as combine it with other data sources our app might be using
</p>
<p>
<strong>Train the model, evaluate its performance, and iterate</strong>
</p>
<p>
Training requires a model architecture (e.g. number of layers, types of layers, operations), data, and the actual training process. We picked a reference <a href="https://arxiv.org/abs/1802.09127">architecture</a> implemented in TensorFlow, and iterated both on the data we used to train it and the architecture itself. In a production workflow we would retrain the model regularly with fresh data to ensure that it continues to behave optimally.
</p>
<p>
In our <a href="https://firebase.google.com/codelabs/iap-optimization#0">codelab</a> we have abstracted away the process of refining the model architecture, so you can still implement this workflow without having much of a background in ML.
</p>
<p>
<strong>Deploy the latest version of the model</strong>
</p>
<p>
Traditional ML models that run in the cloud can be easily updated, just like you would a web application or service. With on-device ML we need a strategy to get the latest model onto the user’s device. The first version can be bundled with the app, so that when the user first installs it there is a version ready to go. Subsequent updates are made by deploying the models to <a href="https://firebase.google.com/products/ml">Firebase ML</a>. With a combination of Remote Config and Firebase ML you can direct users to the right model name (e.g. “active_model = my_model_v1.0.3”), which will then automatically download the latest available model.
</p>
<p>
<strong>Run the model on the device</strong>
</p>
<p>
Once the model is deployed on the device, we use the TensorFlow Lite runtime to “make inferences” or ask questions of the model based on a set of inputs. You can think of this as asking, “What digital good should I show a user based on the following characteristics?” We configured our implementation so that a certain percentage of sessions are shown a random option, which will help us gather new data and keep the model fresh and updated.
</p>
<p>
<strong>Try it yourself!</strong>
</p>
<p>
We have created a <a href="https://firebase.google.com/codelabs/iap-optimization#0">codelab</a> for you to easily follow and replicate these steps in your own app or game. In this implementation you will encounter a scenario similar to HalfBrick's, but we've reduced the number of input features to 6 to make it easier for you to replicate and learn from. You should start with these and iterate as you see fit.
</p>
<p>
We hope you can use this ML workflow to build smarter and more engaging apps for your users and grow your business!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-75485290217440064412022-02-11T12:00:00.000-08:002022-02-11T12:00:13.897-08:00Accept Payments with Cloud Firestore and Google Pay<meta name="twitter:image" content="https://blogger.googleusercontent.com/img/a/AVvXsEhKbqlixfVTLvQ22hdcUWTXGR8sj-FFfYKPJwpZMBK5OdMviI-B2QJNHGGbvxItYs58mb1ubrsUz2FUxtzPgpZdJX_avApwtdeZ9t4Xj73vuSe3UNXpxe5py1LOKRZzqm7wJItai9tfFmAeulMeTbuadahDKicnOVhmU8Uy4Xe2HepZtpXmK5_bHRzNiA">
<img style="display:none" src="https://blogger.googleusercontent.com/img/a/AVvXsEhKbqlixfVTLvQ22hdcUWTXGR8sj-FFfYKPJwpZMBK5OdMviI-B2QJNHGGbvxItYs58mb1ubrsUz2FUxtzPgpZdJX_avApwtdeZ9t4Xj73vuSe3UNXpxe5py1LOKRZzqm7wJItai9tfFmAeulMeTbuadahDKicnOVhmU8Uy4Xe2HepZtpXmK5_bHRzNiA">
<figure class="profile">
<div class="profile-picture">
<img src="https://blogger.googleusercontent.com/img/a/AVvXsEhnpDedRiGQoUFX28TcGrC0qbtuymlUWtuezBKgUnANY15_REhDqRg5Sid-9nOmwa7wb37pHj5JBUn9mNq3uJMXr1KZgetihRPE6Soe8WhMU5BKw3gVoZF8T2hb9916BjMmrbFTNQ73wJ3gMaLLqpI563vRkOl2uc2XV5PFWUUHSl7wfv15Bd9K47XSFQ"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div>Stephen McDonald</div>
</strong>
<em>Developer Relations Engineer, Google Pay</em>
</figcaption>
</figure>
<p>
Back in 2019 we launched <a href="https://firebase.google.com/products/extensions">Firebase Extensions</a> - pre-packaged solutions that save you time by providing extended functionality to your Firebase apps, without the need to research, write, or debug code on your own. Since then, a ton of extensions have been added to the platform covering a wide range of features, from email triggers and text messaging, to image resizing, translation, and much more.
</p>
<h2>Google Pay Firebase Extension</h2>
<p>
We're now excited to have launched a new <a href="https://firebase.google.com/products/extensions/google-pay-make-payment">Google Pay Firebase Extension</a> at Firebase Summit 2021, which brings the ease of the <a href="https://developers.google.com/pay/api">Google Pay API</a> to your Firebase apps.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhKbqlixfVTLvQ22hdcUWTXGR8sj-FFfYKPJwpZMBK5OdMviI-B2QJNHGGbvxItYs58mb1ubrsUz2FUxtzPgpZdJX_avApwtdeZ9t4Xj73vuSe3UNXpxe5py1LOKRZzqm7wJItai9tfFmAeulMeTbuadahDKicnOVhmU8Uy4Xe2HepZtpXmK5_bHRzNiA" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image that says Make payments with Google Pay" border="0" data-original-height="348" data-original-width="1600" src="https://blogger.googleusercontent.com/img/a/AVvXsEhKbqlixfVTLvQ22hdcUWTXGR8sj-FFfYKPJwpZMBK5OdMviI-B2QJNHGGbvxItYs58mb1ubrsUz2FUxtzPgpZdJX_avApwtdeZ9t4Xj73vuSe3UNXpxe5py1LOKRZzqm7wJItai9tfFmAeulMeTbuadahDKicnOVhmU8Uy4Xe2HepZtpXmK5_bHRzNiA"/></a></div>
<p>
With the Google Pay Firebase Extension, your app can accept payments from Google Pay users, using one or more of the many supported Payment Service Providers (or PSPs), without the need to invoke their individual APIs.
</p>
<p>
With the extension installed, your app can pass a payment token from the <a href="https://developers.google.com/pay/api">Google Pay API</a> to your <a href="https://firebase.google.com/docs/firestore">Cloud Firestore database</a>. The extension will listen for a request written to the path defined during installation, and then send the request to the PSP's API. It will then write the response back to the same Firestore node, which you can listen and respond to in real time.
</p>
<h2>Open Source</h2>
<p>
Like all Firebase Extensions, the Google Pay Firebase Extension is <a href="https://github.com/google-pay/firebase-extension">entirely open source</a>, so you can modify the code yourself to change the functionality as you see fit, or even contribute your changes back via pull requests - the sky's the limit.
</p>
<h2>Summing it up</h2>
<p>Whether you're new to Google Pay or Firebase, or an existing user of either, the new <a href="https://firebase.google.com/products/extensions/google-pay-make-payment">Google Pay extension</a> is designed to save you even more time and effort when integrating Google Pay and any number of Payment Service Providers with your application.</p>
<p>
Get started with the <a href="https://firebase.google.com/products/extensions/google-pay-make-payment">Google Pay extension</a> today.
</p>
Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-8085194714299613232022-01-26T10:22:00.000-08:002022-01-26T10:22:12.870-08:00Everything you need to know about Remote Config’s latest personalization feature<meta name="https://blogger.googleusercontent.com/img/a/AVvXsEispVAhftRUtYLTnuemBRGFogka2_1RlqBYKeBQw3pFrhxvCxL34smurbzAogrUV_TrOop9w6l-nKq0OoJ_7ETz6W0hVyUxMt37zi4gOT9wH30FyB64Ar9LAbk93RD-X3749oq6r-XQXSzCgTpIvXGhGZrESghp0r-ITqnQkDoqN53i_iIVOBOjxz2vBA">
<img style="display:none" src="https://blogger.googleusercontent.com/img/a/AVvXsEispVAhftRUtYLTnuemBRGFogka2_1RlqBYKeBQw3pFrhxvCxL34smurbzAogrUV_TrOop9w6l-nKq0OoJ_7ETz6W0hVyUxMt37zi4gOT9wH30FyB64Ar9LAbk93RD-X3749oq6r-XQXSzCgTpIvXGhGZrESghp0r-ITqnQkDoqN53i_iIVOBOjxz2vBA">
<figure class="profile">
<div class="profile-picture">
<img src="https://blogger.googleusercontent.com/img/a/AVvXsEhZu82AzTBpjuNNxYlcUlQK3VBseORpb_kDXpNYNkM1x7xkoMddMr0BVsi7aJxCOcaSIAixjKixRbn37du1qOcShzLniahJ-lrZlFhLJBQ-3oq49RLWaU7gQtHvjacFVxvgKm7pG7cije9QZQmcJ_Fv6JnQjqmBNFSTOJ8SyoKAKxq-VngaRikswYjcsg"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div>Jon Mensing</div>
</strong>
<em>Product Manager</em>
</figcaption>
</figure>
<p>
An important part of turning your app into a business is to optimize your user experience to drive the bottom line results you want. A popular way to do this is through manual experimentation, which involves setting up A/B tests for different components of your app and finding the top performing variant. Now, you can save time and effort - and still maximize the objectives you want - with Remote Config’s latest personalization feature. <strong>Personalization harnesses the power of machine learning to <em>automatically</em> find the optimal experience for each user to produce the best outcomes, taking the load off you. </strong><br>
</p>
<p>
At <a href="https://firebase.googleblog.com/2021/11/whats-new-at-Firebase-Summit-2021.html">Firebase Summit 2021</a>, we announced that Remote Config personalization is officially available in beta! Let’s take a closer look at this new feature, how it differs from A/B testing, and how you can use it today to grow your business.
</p>
<h2>What is Remote Config personalization?</h2>
<p>
<a href="https://firebase.google.com/products/remote-config">Remote Config</a> lets you dynamically control and change the behavior and appearance of your app without releasing a new version or setting up any complex infrastructure. You can use Remote Config to implement feature flags, perform A/B tests, customize your app for different user segments, and now, with personalization, optimize your user experience with minimal work. All you need to do is specify the objective you want to maximize, and personalization will continuously find and apply the right app configuration for each user, taking their behavior and preferences into account and tracking impact on secondary metrics along the way. For example, you can personalize the difficulty of your game according to player skill levels to maximize engagement and session duration.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhXBD2P5ia7lL5ljdNrCoAscY8rrYecYBWMBeS-mHdLcb1BIArfD33x09AvVZl4PwTnGFD3st4p7ODqdzBep_wJVvSsV2OaNtGfMyeQGzw0S_idKOx-ncNz6XrW8apojdkzryp8UZ5MqAXcwZcpR55t7EBL1AKNr6PAucGBU2k8ADkjdTQfvu7WMMu-Gg" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image from Firebase Summit showing animated characters" border="0" data-original-height="488" data-original-width="1382" src="https://blogger.googleusercontent.com/img/a/AVvXsEhXBD2P5ia7lL5ljdNrCoAscY8rrYecYBWMBeS-mHdLcb1BIArfD33x09AvVZl4PwTnGFD3st4p7ODqdzBep_wJVvSsV2OaNtGfMyeQGzw0S_idKOx-ncNz6XrW8apojdkzryp8UZ5MqAXcwZcpR55t7EBL1AKNr6PAucGBU2k8ADkjdTQfvu7WMMu-Gg"/></a></div>
<h2>How does Remote Config personalization differ from A/B testing?</h2>
<p>
A/B testing and personalization are both good frameworks for app optimization. While they share some similarities, there are a few big differences that are worth pointing out. First, A/B testing requires you to be hands-on throughout the whole process - from setting up the experiment, determining the variables, monitoring and analyzing results, to rolling out the winning variant. With personalization, you determine the experiences you want to try and state the objective you want to maximize. Then, the personalization algorithm uses machine learning to do the rest. It automatically tries different alternatives with different users, learns which alternatives work best, and chooses the alternative that is predicted to maximize your objective.
</p>
<p>
Second, A/B testing finds a single, <em>global optimum, </em>while personalization gets more granular to find the optimum treatment for <em>each user</em> so you’re not leaving value on the table.
</p>
<p>
And a third important difference is the timing required for each feature. A/B testing usually takes at least a few weeks to run an experiment and return a result, whereas personalization goes to work immediately, optimizing selections from the moment it is enabled.
</p>
<h2>When should you use A/B testing vs. Remote Config personalization? </h2>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgn4c_ZV12bffvXkggQNm_dq0Slzrvxsx2mbW4NgL4nhEProzSURSzRWhbidGJDa76Ex482GuPkx_vwp05lD5nhb24PhYDjphiBkdLVtH4GFyp4NgycbO2z4UiSOKVnl2wjD7RUkIWmxPCEIUvkdQkeeG43pnbcA_cw7tfRxHxh6PlnSu42PstCSGVIsQ" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Table showing when to use A/B testing vs Remote Config personalization" border="0" data-original-height="764" data-original-width="1282" src="https://blogger.googleusercontent.com/img/a/AVvXsEgn4c_ZV12bffvXkggQNm_dq0Slzrvxsx2mbW4NgL4nhEProzSURSzRWhbidGJDa76Ex482GuPkx_vwp05lD5nhb24PhYDjphiBkdLVtH4GFyp4NgycbO2z4UiSOKVnl2wjD7RUkIWmxPCEIUvkdQkeeG43pnbcA_cw7tfRxHxh6PlnSu42PstCSGVIsQ"/></a></div>
<p>
Halfbrick, the game studio behind titles like Jetpack Joyride, Dan the Man, and the instant-classic Fruit Ninja, <a href="https://firebase.google.com/use-cases/halfbrick-personalization">used personalization to optimize ad frequency</a>, which led to a 16% increase in revenue without affecting engagement or retention. They also used personalization to determine the best time (i.e. when users are most enjoying the game) to ask users to rate their app, and were able to boost positive app store ratings by 15%.
</p>
<p>
In their own words:
</p>
<p>
<em>"The granularity achieved with Remote Config's personalization feature is impossible for a human to instrument. Personalization has given us new insight into how we can optimize our ad strategy and even helped us challenge our own assumptions that players don't like too many ads." </em>
</p>
<p>
<em><br></em>— Miguel Pastor, Product Manager, Halfbrick
</p>
<p>
Ahoy Games, another early customer, tried personalization in a number of their games and successfully <a href="https://firebase.google.com/use-cases/ahoy-games">grew in-app purchases by 12-13%</a> with little to no effort from their team.
</p>
<p>
Their CEO, Deniz Piri, had this to say:
</p>
<p>
<em>“We are very impressed with how magical the personalization feature has been. It's so much more than an A/B test, as it continuously optimizes and serves the right variant to the right groups of people to maximize conversion goals. Without Firebase, we would have a harder time succeeding in an arena full of bigger corporations with our humble 13-person team.”</em>
</p>
<h2>How to set up personalization in your app</h2>
<p>
Let’s walk through an example - say you wanted to personalize the moment you show an ad to players in your game based on how many levels they’ve completed, with the objective of maximizing the number of ad clicks generated in a gaming session.
</p>
<p>
We’ll suppose you have three alternatives that personalization can choose from:
</p>
<ol>
<li>Show an ad after every level completed
<li>Show an ad after every three levels completed
<li>Show an ad after every seven levels completed
</li>
</ol>
<p>
Let’s look at how you can set this up in your application using Remote Config.
</p>
<p>
Alternatively, you can also <a href="https://www.youtube.com/watch?v=MTclqADW9rs">check out this video walkthrough</a> of the personalization feature which includes an overview and an example on how to personalize the timing for showing an app rating prompt to maximize the likelihood of users submitting a review. You can also check out the personalization documentation for complete instructions on <a href="https://firebase.google.com/docs/remote-config/personalization/get-started">getting started with personalization</a>.
</p>
<p>
The first step will be to go into the Firebase console and into the Remote Config section to create an RC parameter that can be used to provide one of these alternatives in your application. This can be done by navigating to the <em>Firebase console > Remote Config</em> and clicking on <em>“Create configuration”</em> if it’s your first time using Remote Config, or <em>“Add parameter”</em> if you already have some created. This will open up the parameter editor as shown below.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgGDdmzDh6XqW4COyrdgO8DPOXXOBOgrF-eaonUFyma-rX1DplRpRNbahbroPKgONP9kTN_kJ9ywOaiCBO86uQhFdL9hHKxP8IQ3LO2V7ns702tC0GKjliSduLfAAxVEP3WPpeSLxe2lX8javzbvto9d3w5T-OA0w-4XtXKArFHyDTVmRE_E_PVPo3SoA" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image showing create parameter" border="0" data-original-height="950" data-original-width="1190" src="https://blogger.googleusercontent.com/img/a/AVvXsEgGDdmzDh6XqW4COyrdgO8DPOXXOBOgrF-eaonUFyma-rX1DplRpRNbahbroPKgONP9kTN_kJ9ywOaiCBO86uQhFdL9hHKxP8IQ3LO2V7ns702tC0GKjliSduLfAAxVEP3WPpeSLxe2lX8javzbvto9d3w5T-OA0w-4XtXKArFHyDTVmRE_E_PVPo3SoA"/></a></div>
<p>
Next, click on <em>Add new > Personalization</em> which will open the personalization editor where you can specify alternative values for the parameter, select the primary objective, as well as set additional metrics and targeting conditions for the personalization. In this example, I’m using ad clicks as the primary optimization goal, and tracking user engagement as a secondary metric to monitor as personalization delivers personalized values to users.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiz5BmprJ1oWLxSQMG9veG-R6eWefaYjwpqQW-4hkj-UAF4Lj67qgkvr1KM6nnL1kN52ebWe-7wpsmyEP9ufNdgMBf6LtOeWZRGZ93byHUJuNJwlsIeKjlXoaGX9N4f5uNhogX-QnvY8NuN8BLA-fQJPUx5pt9hG0L0mq3Lv5zRIIR84DxZuo6FXfVC9g" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Screenshot 1" border="0" data-original-height="1536" data-original-width="1800" src="https://blogger.googleusercontent.com/img/a/AVvXsEiz5BmprJ1oWLxSQMG9veG-R6eWefaYjwpqQW-4hkj-UAF4Lj67qgkvr1KM6nnL1kN52ebWe-7wpsmyEP9ufNdgMBf6LtOeWZRGZ93byHUJuNJwlsIeKjlXoaGX9N4f5uNhogX-QnvY8NuN8BLA-fQJPUx5pt9hG0L0mq3Lv5zRIIR84DxZuo6FXfVC9g"/></a></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhA1DW6VtFJUl3AW7Vr6apBma-lpjhM8pu5bvFmVTwhJnj3MHuWpmCa-8FP_gltn4Cv2UspHOpX3jL3w3dyzImgIknLXEw6sEMZQge3udNuXtCvCgcV4Q60N-GsMi-4MxZy2_BOLrIdxxseIlhAm0ik-TMV6Yq4Ii3IxtnfIvViKTK1I_YbZaOjDSvE8A" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="How to create a personalized parameter, including personalization goals and additional metric tracking within a few clicks in the Remote Config parameter editor" border="0" data-original-height="1100" data-original-width="1700" src="https://blogger.googleusercontent.com/img/a/AVvXsEhA1DW6VtFJUl3AW7Vr6apBma-lpjhM8pu5bvFmVTwhJnj3MHuWpmCa-8FP_gltn4Cv2UspHOpX3jL3w3dyzImgIknLXEw6sEMZQge3udNuXtCvCgcV4Q60N-GsMi-4MxZy2_BOLrIdxxseIlhAm0ik-TMV6Yq4Ii3IxtnfIvViKTK1I_YbZaOjDSvE8A"/></a></div>
<p id="imgCaption"> How to create a personalized parameter, including personalization goals and additional metric tracking within a few clicks in the Remote Config parameter editor. </p>
<p>
Now you’ll just need to click on “<em>Save</em>” and “<em>Publish changes</em>” to make the new parameter available to any running application instances. The final step is to implement and use your new Remote Config parameter in your application code. You can follow the <a href="https://firebase.google.com/docs/remote-config/get-started">getting started guide</a> to complete these final steps based on which platform your app is targeting.
</p>
<p>
From here, personalization will go to work immediately, selecting the best predicted alternative for each user, and collecting metrics along the way to help you determine the effectiveness of personalization in optimizing towards your primary goal. Over time, you’ll see a results summary screen similar to the one in the screenshot below:
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgmzEZZ5JCzCvEVmtcWBNpO9ZkWW8qirRgQZHdBqz3gG1JUamxmsPUwauSEKqMLHj7dY-LBHbetSlhTulvH1AKkjniNFlL6saNKTPNI2soqFY8JYFi30z8MXISAAH_rd9hhtyog6ahEtKHWVpKS-7OY-zlumvETAnQgFsgZEhT6eSynnz0__IF7pOFh2g" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Screenshot of Personalization in Firebase" border="0" data-original-height="1248" data-original-width="1888" src="https://blogger.googleusercontent.com/img/a/AVvXsEgmzEZZ5JCzCvEVmtcWBNpO9ZkWW8qirRgQZHdBqz3gG1JUamxmsPUwauSEKqMLHj7dY-LBHbetSlhTulvH1AKkjniNFlL6saNKTPNI2soqFY8JYFi30z8MXISAAH_rd9hhtyog6ahEtKHWVpKS-7OY-zlumvETAnQgFsgZEhT6eSynnz0__IF7pOFh2g"/></a></div>
<p>
The box in gray represents the baseline holdout group, while the box in blue represents the group of users who’ve received personalized values. The total lift shows how much additional value personalization has generated relative to the holdout group that didn’t receive personalized values. Since the baseline group will be much smaller than the personalization group, the numbers in the baseline holdout group are scaled up so that the numbers are comparable, and the total lift can be calculated. You can also breakdown baseline performance details to see how each alternative value performed individually.
</p>
<p>
As time goes by, you can revisit the results summary page to ensure that the personalization is continuing to deliver more value than the baseline group, maximizing your goal automatically as personalization and Remote Config do their work.
</p>
<p>
Now that personalization is available in public beta you can start scaling your app today without scaling your effort. Check it out in the Firebase console today, or <a href="https://firebase.google.com/docs/remote-config/personalization">take a look at our documentation</a> to learn more.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-71622127784166972302021-11-10T09:31:00.000-08:002021-11-10T09:31:23.219-08:00What’s new at Firebase Summit 2021<meta name="twitter:image" content="https://1.bp.blogspot.com/-MXn_kNo8yFI/YYWPCtkQxmI/AAAAAAAAF-8/tehHlefn3xcnqNmV7xTvhSwKQfFfFwOLQCLcBGAsYHQ/s0/FBS21_Blog_v3.png">
<img style="display:none" src="https://1.bp.blogspot.com/-MXn_kNo8yFI/YYWPCtkQxmI/AAAAAAAAF-8/tehHlefn3xcnqNmV7xTvhSwKQfFfFwOLQCLcBGAsYHQ/s0/FBS21_Blog_v3.png">
<figure class="profile">
<div class="profile-picture">
<img src="https://1.bp.blogspot.com/-r8ZkyJO25Jo/YYWQozyZnaI/AAAAAAAAF_E/gUdQQ6ZPsEw0gEZHqdu_TkZmVAe8gnH1ACLcBGAsYHQ/s0/0002_Kristen_Johnson_Google_Tricia_McCormack_Photography.jpeg"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div>Kristen Richards</div>
</strong>
<em>Group Product Manager</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-MXn_kNo8yFI/YYWPCtkQxmI/AAAAAAAAF-8/tehHlefn3xcnqNmV7xTvhSwKQfFfFwOLQCLcBGAsYHQ/s0/FBS21_Blog_v3.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Whats new at Firebase Summit" border="0" data-original-height="512" data-original-width="1024" src="https://1.bp.blogspot.com/-MXn_kNo8yFI/YYWPCtkQxmI/AAAAAAAAF-8/tehHlefn3xcnqNmV7xTvhSwKQfFfFwOLQCLcBGAsYHQ/s0/FBS21_Blog_v3.png"/></a></div>
<p>
Here at Firebase, we believe developers play an instrumental role in helping people learn, live better, go places, and grow businesses. That’s why we’re committed to providing you with integrated, easy-to-use, and extensible tools so you can continue to create experiences that billions of people not only rely on, but love.
</p>
<p>
Millions of apps actively use Firebase every month, created by businesses of all sizes, from startups to global enterprises. Your trust in us is what motivates and inspires us to make Firebase even better. Today, Firebase Summit is returning as a virtual event and we’re excited to unveil updates to our platform that will help you accelerate app development, run your app with confidence, and scale with ease. Read on for more details on what’s new, and don’t forget to check out all of the great content (including technical sessions, demos, pathways, and more) from the summit on our <a href="https://firebase.google.com/summit">event website</a>!
</p>
<p><em>Jump to a particular section if you’re short on time, or read the entire article below.</em></p>
<strong>Accelerate app development with new building blocks</strong>
<ul>
<li><u><a href="#New" style="color: black;">New Extensions for adding critical e-commerce features in less time</a></u>
</li><li><u><a href="#Enhanced" style="color: black;">Enhanced support for Apple platforms, game engines, and Flutter</a></u>
</li><li><u><a href="#Strengthening" style="color: black;">Strengthening app security with App Check</a></u>
</li><li><u><a href="#Detailed" style="color: black;">Detailed documentation for upcoming Google Play Safety policies</a></u>
</ul>
<p><strong>Gain actionable insights to run your app with confidence </strong></p>
<ul>
<li><u><a href="#real-time" style="color: black;">New real-time alerts in Performance Monitoring</a></u>
</li><li><u><a href="#Crashlytics" style="color: black;">Crashlytics adds Application Not Responding (ANR) reports and signals</a></u>
</ul>
<p><strong>Scale with ease by using powerful engagement tools</strong></p>
<ul>
<li><u><a href="#Unified" style="color: black;">Unified campaign management for Cloud Messaging and In-App Messaging</a></u>
</li><li><u><a href="#Remote" style="color: black;">Remote Config core improvements and beta launch of personalization</a></u>
</ul>
<h2>Accelerate app development with new building blocks</h2>
<p>
Firebase helps you get your app up and running by providing fully-managed infrastructure, with a streamlined experience, that lets you focus on what matters most.
</p>
<a name="New" style="color: black;"><h3>New Extensions for adding critical e-commerce features in less time</h3>
<p>
<a href="https://firebase.google.com/products/extensions">Firebase Extensions</a> are pre-packaged bundles of code that automate common development tasks and let you add functionality to your app in fewer steps. We’ve been partnering with companies you know and trust so you can integrate multiple services without learning new APIs. Our friends at Stripe recently added one-time payments and an <a href=" https://www.npmjs.com/package/@stripe/firestore-stripe-payments">SDK</a> to their <a href="https://firebase.google.com/products/extensions/stripe-firestore-stripe-payments">Run Payments with Stripe</a> extension. Plus, they just launched a new feature that lets you accept over 15 different payment methods including wallets, bank redirects, and "Buy now, Pay later" within your app.
</p>
<p>
We’re also unveiling <strong>new Extensions for adding critical e-commerce features</strong> to your app in less time. These Extensions can help you ship and track merchandise with ShipEngine, re-engage users who abandon their shopping carts with SendGrid emails or SMS messages via Twilio, and implement search on Cloud Firestore with Elastic. You can even add a single interface to accept payments from multiple providers through Google Pay - which is especially handy if you’re launching your app internationally. For more details, go to the <a href="https://firebase.google.com/products/extensions">Firebase Extensions page</a> and install them today! And if you need inspiration to get started, check out the code for our <a href="https://github.com/FirebaseExtended/karas-coffee">sample app on GitHub</a> that uses over 17 different Extensions and view the deployed version at: <a href="https://karas-coffee.web.app/">https://karas-coffee.web.app/</a>.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-59jQe6UueWc/YYW3324p7cI/AAAAAAAAF_c/5CfsEr2v6dsECfGev9IeZto85eLQf_9oACLcBGAsYHQ/s0/FB%2BRecap%2Bblog%2B1.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="These new Extensions, built by our partners in collaboration with Firebase, help you add e-commerce features to your app much faster" border="0" data-original-height="654" data-original-width="1356" src="https://1.bp.blogspot.com/-59jQe6UueWc/YYW3324p7cI/AAAAAAAAF_c/5CfsEr2v6dsECfGev9IeZto85eLQf_9oACLcBGAsYHQ/s0/FB%2BRecap%2Bblog%2B1.png"/></a></div>
<p id="imgCaption"> These new Extensions, built by our partners in collaboration with Firebase, help you add e-commerce features to your app much faster </p>
<a name="Enhanced" style="color: black;"><h3>Enhanced support for Apple platforms, game engines, and Flutter</h3>
<p>
We’re excited to announce that Firebase now offers<strong> beta level support for tvOS and macOS</strong>! This means you can use your favorite Firebase products to build and run apps that are compatible with Apple TVs and Macbooks - from a single codebase - and deliver a great, cross-device experience to users with less hassle. For example, when you add the Crashlytics SDK, you can identify critical crashes and even filter crashes by Apple device type or operating system right from the Firebase Crashlytics console.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-qRJLBKbWOGU/YYW57mhzH5I/AAAAAAAAF_k/P7VDaTvf7hEj9371qAYQF3QNh4BxxMVYACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B2.gif" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="With enhanced support for Apple platforms, you can deliver a smooth cross-device experience" border="0" data-original-height="607" data-original-width="1080" src="https://1.bp.blogspot.com/-qRJLBKbWOGU/YYW57mhzH5I/AAAAAAAAF_k/P7VDaTvf7hEj9371qAYQF3QNh4BxxMVYACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B2.gif"/></a></div>
<p id="imgCaption"> With enhanced support for Apple platforms, you can deliver a smooth cross-device experience </p>
<p>
If you’re a game developer, you’ll be happy to learn that many of <strong>our C++ SDKs now support Apple TV</strong>, so you can develop phenomenal Apple Arcade games with Firebase! On top of that, we’re expanding support for game frameworks and engines by making <strong>Cloud Firestore available for Unity and C++</strong>. This lets you add the power of Cloud Firestore to your game in seconds to store and sync your game data in near real-time, add offline support, and scale your game experience to support thousands of players.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-WFbVTYy4whw/YYW7J7pSU2I/AAAAAAAAF_s/CZrsXkHVyHIeWge_qvAi-0bqlL-jqk6NACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B3.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:65%" alt="Cloud Firestore is now available for Unity and C++, giving you real-time data synchronization capabilities and offline support" border="0" data-original-height="676" data-original-width="506" src="https://1.bp.blogspot.com/-WFbVTYy4whw/YYW7J7pSU2I/AAAAAAAAF_s/CZrsXkHVyHIeWge_qvAi-0bqlL-jqk6NACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B3.png"/></a></div>
<p id="imgCaption"> Cloud Firestore is now available for Unity and C++, giving you real-time data synchronization capabilities and offline support </p>
<p>
We’ve also made a number of big <strong>improvements to Crashlytics’ Unity and NDK SDKs</strong> to make it easier to debug your game’s codebase. Now, Crashlytics tracks a wider range of native crash types, and includes IL2CPP support for Unity games to show more symbolicated C++ frames that can be mapped to your C# code.
</p>
<p>
Finally, with the latest release of Dartpad, Flutter’s online editor, you can use <a href="https://flutter.dev/">Flutter</a> and Firebase together to develop apps that reach users across platforms with just your browser. Flutter is Google's open source framework for building beautiful, natively compiled, multi-platform apps from a single codebase. It's a natural complement to Firebase's cross-platform backend services. Today, <strong>Dartpad supports Cloud Firestore and Firebase Authentication</strong>, with other Firebase products coming soon! Go to <a href="dartpad.dev">dartpad.dev</a> and import the Firebase packages to get started. You can also take a look at our <a href="https://dartpad.dev/?id=ba3b2530d348775da2cb357d60d4afbf&null_safety=true">sample app.</a>
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-WSMT5ImQYZ4/YYW73Mgz8-I/AAAAAAAAF_0/4RxuJEFcGgYt7LaC3m2i6iq7LaAy2R5gwCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B4.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Dartpad, Flutter’s online editor, now gives you support for Firebase right out of the box" border="0" data-original-height="900" data-original-width="1600" src="https://1.bp.blogspot.com/-WSMT5ImQYZ4/YYW73Mgz8-I/AAAAAAAAF_0/4RxuJEFcGgYt7LaC3m2i6iq7LaAy2R5gwCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B4.png"/></a></div>
<p id="imgCaption"> Dartpad, Flutter’s online editor, now gives you support for Firebase right out of the box </p>
<a name="Strengthening" style="color: black;"><h3>Strengthening app security with App Check</h3>
<p>
A few months ago, we introduced you to App Check, which provides a powerful layer of security for your backend infrastructure. It does this by attesting that incoming traffic is coming from your app on a legitimate device, and blocking traffic that doesn't have valid credentials. Today, App Check can do even more because we’ve made three major updates.
</p>
<p>
First, you can now <strong>use App Check to protect access to Cloud Firestore </strong>(with Firestore Web SDK support coming soon), in addition to Cloud Storage for Firebase, Realtime Database and Cloud Functions for Firebase that we announced previously. Second, <strong>we’ve added custom server protections</strong> so you can use App Check with any custom backend resources. It even integrates with API Management Platforms like Apigee and CDNs like CloudFlare. Third, we’ve expanded the number of attestation providers App Check supports to <strong>now include Apple’s app attestation provider App Attest and reCAPTCHA Enterprise</strong>. Register your app with App Check today and start enforcing protections through the Firebase console. To learn more about App Check, check out our <a href="https://firebase.google.com/docs/app-check">documentation</a>.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-1N9D-9m3gNo/YYW8PmNB4yI/AAAAAAAAF_8/w7mfuZplStIk_ovGjdCKuv3AdwHnPBnagCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B5.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="App Check protects your app and user data" border="0" data-original-height="712" data-original-width="1600" src="https://1.bp.blogspot.com/-1N9D-9m3gNo/YYW8PmNB4yI/AAAAAAAAF_8/w7mfuZplStIk_ovGjdCKuv3AdwHnPBnagCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B5.png"/></a></div>
<p id="imgCaption"> App Check protects your app and user data </p>
<a name="Detailed" style="color: black;"><h3>Detailed documentation for upcoming Google Play Safety policies</h3>
<p>
We’re launching <strong><a href="https://firebase.google.com/docs/android/play-data-disclosure">detailed documentation</a></strong> that specifies what data each Firebase product collects and shares to help you comply with <a href="https://android-developers.googleblog.com/2021/10/launching-data-safety-in-play-console.html">Google Play’s upcoming safety policies</a>. Our goal is to build upon Google’s commitment to privacy and transparency, and give you a head start to prepare for Google Play’s new data safety section, which launches to app users next year.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-5g1-UlsBDaE/YYW8zCAsWUI/AAAAAAAAGAE/e_cRzzaEz84wjKxSsOtu4qJF5M1Fd9FbwCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B6.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="The above image is an example only and subject to change" border="0" data-original-height="900" data-original-width="1600" src="https://1.bp.blogspot.com/-5g1-UlsBDaE/YYW8zCAsWUI/AAAAAAAAGAE/e_cRzzaEz84wjKxSsOtu4qJF5M1Fd9FbwCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B6.png"/></a></div>
<p id="imgCaption"> The above image is an example only and subject to change </p>
<h2>Gain actionable insights to run your app with confidence </h2>
<p>
With Firebase, you can monitor your app’s performance and stability, test changes, and get insight on how you can resolve issues to deliver the best experience possible.
</p>
<a name="real-time" style="color: black;"><h3>New real-time alerts in Performance Monitoring</h3>
<p>
<a href="https://firebase.google.com/products/performance">Firebase Performance Monitoring</a> gathers and presents data about your app’s performance, so you know exactly what’s happening in your app –and when users are experiencing slowness– from their point of view. However, no matter how thoroughly you test your app on your local machine, your app can still run into latency issues because users will access it on different devices, from different countries, and on different network speeds. To keep you informed, we’re releasing a <strong>new feature called performance alerts </strong>in beta! These new <a href="https://firebase.google.com/docs/perf-mon/alerts">performance alerts</a> will send you an email when your app start time exceeds a given threshold so you can investigate and fix the latency issue as soon as it appears. Performance alerts can be configured from the console and we’ll be adding more alerts for other<strong> </strong>performance metrics soon.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-ZrQuw-9joQI/YYXACuaV9WI/AAAAAAAAGAQ/6_SFUXltpqkHkitP07s3BaAiMD9AjJkeQCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B7.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:80%" alt="Performance Monitoring’s new real-time alerts will let you know if your app start time slows down" border="0" data-original-height="878" data-original-width="710" src="https://1.bp.blogspot.com/-ZrQuw-9joQI/YYXACuaV9WI/AAAAAAAAGAQ/6_SFUXltpqkHkitP07s3BaAiMD9AjJkeQCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B7.png"/></a></div>
<p id="imgCaption"> Performance Monitoring’s new real-time alerts will let you know if your app start time slows down </p>
<a name="Crashlytics" style="color: black;"><h3>Crashlytics adds Application Not Responding (ANR) reports and signals</h3>
<p>
<a href="https://firebase.google.com/products/crashlytics">Firebase Crashlytics</a> gives you a complete view into your app’s stability so you can track, prioritize, and resolve bugs before they impact a large number of users. On top of Crashlytics' enhanced support for Apple platforms and game reporting, <strong>Crashlytics now reports Application Not Responding (ANRs) errors</strong>! According to our research, ANRs account for almost 50% of all unintended application exits on Android, meaning they can be more detrimental to your app’s quality than crashes. To give you a comprehensive view of your app’s stability issues, Crashlytics now reports ANRs and surfaces contextual information about impacted threads so you can pinpoint the cause of the ANR.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-gsoKOg4QVns/YYXFFTMMHjI/AAAAAAAAGAY/HYo0y194wAw6iwD1vDEUpGidVLWjIqJJACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B8.gif" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Crashlytics now reports Application Not Responding errors, giving you a more comprehensive view of app stability" border="0" data-original-height="702" data-original-width="1118" src="https://1.bp.blogspot.com/-gsoKOg4QVns/YYXFFTMMHjI/AAAAAAAAGAY/HYo0y194wAw6iwD1vDEUpGidVLWjIqJJACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B8.gif"/></a></div>
<p id="imgCaption"> Crashlytics now reports Application Not Responding errors, giving you a more comprehensive view of app stability </p>
<p>
We’re also unveiling a<strong> new concept in Crashlytics called signals</strong>. Signals analyze your crashes to uncover interesting commonalities and characteristics that are helpful for troubleshooting. Today, we’re launching with three signals: early crashes, fresh issues, and repetitive issues. Early crashes refer to crashes that users experience near app start. Fresh issues are new issues in the last 7 days, while repetitive issues are issues that users have been encountering over and over again. Signals are available to both Apple and Android app developers. Check them out during your next app release!
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Pniz8hTGXHI/YYXHx1MdkxI/AAAAAAAAGAg/_NBrulustvgOApz1-LXffwVOavRqwwe3wCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B9.gif" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Crashlytics signals surface interesting commonalities and characteristics of crashes to improve troubleshooting" border="0" data-original-height="702" data-original-width="1118" src="https://1.bp.blogspot.com/-Pniz8hTGXHI/YYXHx1MdkxI/AAAAAAAAGAg/_NBrulustvgOApz1-LXffwVOavRqwwe3wCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B9.gif"/></a></div>
<p id="imgCaption"> Crashlytics signals surface interesting commonalities and characteristics of crashes to improve troubleshooting </p>
<h2>Scale with ease by using powerful engagement tools</h2>
<p>
As your app grows, Firebase offers the control, automation, and flexibility you need to drive the business outcomes you want, such as increasing engagement and revenue.
</p>
<a name="Unified" style="color: black;"><h3>Unified campaign management for Cloud Messaging and In-App Messaging</h3>
<p>
<a href="https://firebase.google.com/products/cloud-messaging">Firebase Cloud Messaging</a> makes it easy to send targeted, automated, and customized push notifications across platforms so you can reach users <em>even when they aren’t actively using your app</em>. <a href="https://firebase.google.com/products/in-app-messaging">Firebase In-App Messaging</a> gives you the ability to send contextual messages to users who <em>are actively using your app</em> so you can encourage them to complete key in-app actions. These two products go hand-in-hand in keeping users engaged. That’s why we’re thrilled to reveal a <strong>redesigned console experience</strong> that brings them together. This unified dashboard gives you a holistic view into all of your messaging campaigns, so you can run sophisticated, multi-touch campaigns for different audiences and see how they perform – from one place. For example, you can send a coupon code to users who are predicted to churn to keep them around because both Cloud Messaging and In-App Messaging work seamlessly with <a href="https://support.google.com/analytics/answer/9805833">Google Analytics’ new Predictive Audiences</a>. To try the new unified dashboard, visit the console and click the “Preview now” button.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-an7icl5rMO8/YYXIPwrhybI/AAAAAAAAGAo/s3EzUjBdTvQJFWWOFGOoCnWErdcJoK1bACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B10.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Try a new preview of Firebase messaging" border="0" data-original-height="238" data-original-width="1600" src="https://1.bp.blogspot.com/-an7icl5rMO8/YYXIPwrhybI/AAAAAAAAGAo/s3EzUjBdTvQJFWWOFGOoCnWErdcJoK1bACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B10.png"/></a></div>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-uu6puBbi8AI/YYXIgmwo86I/AAAAAAAAGAw/-kxWNg47O80n5H9VvIGsces3XVIGLkxrgCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B11.gif" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="The unified dashboard for Cloud Messaging and In-App Messaging lets you view and manage your campaigns from one place" border="0" data-original-height="847" data-original-width="1005" src="https://1.bp.blogspot.com/-uu6puBbi8AI/YYXIgmwo86I/AAAAAAAAGAw/-kxWNg47O80n5H9VvIGsces3XVIGLkxrgCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B11.gif"/></a></div>
<p id="imgCaption"> The unified dashboard for Cloud Messaging and In-App Messaging lets you view and manage your campaigns from one place </p>
<a name="Remote" style="color: black;"><h3>Remote Config core improvements and beta launch of personalization</h3>
<p>
Another way to retain and delight users is by personalizing the app experience to suit their needs and preferences. With <a href="https://firebase.google.com/products/remote-config">Firebase Remote Config</a>, you can dynamically control and change the way your app looks and behaves without releasing a new version. Today, we’re excited to launch a <strong>new Remote Config feature called personalization</strong> into beta! <a href="https://firebase.google.com/docs/remote-config/personalization?authuser=0">Personalization</a> gives you the ability to <em>automatically</em> optimize individual user experiences to maximize the objectives you care about through the power of machine learning. After a simple setup, personalization will continuously find and apply the right app configuration for each user to produce the best outcome, taking the load off of you.
</p>
<p>
Halfbrick, the game studio behind titles like Jetpack Joyride, Dan the Man, and the instant-classic Fruit Ninja, has already used personalization to <a href="https://firebase.google.com/use-cases/halfbrick-personalization">increase revenue by 16%</a> and boost positive app store ratings by 15%! Ahoy Games, another early customer, tried personalization in a number of their games and successfully <a href="https://firebase.google.com/use-cases/ahoy-games">grew in-app purchases by 12-13%</a> with little to no effort from their team.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-qUD8_rbNFS0/YYXI1FZeTaI/AAAAAAAAGA4/8QPyjT679Bg6ome8udb_7aDVEb7kqdevACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B12.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Remote Config personalization uses machine learning to help you optimize user experiences to achieve your goals" border="0" data-original-height="1002" data-original-width="1534" src="https://1.bp.blogspot.com/-qUD8_rbNFS0/YYXI1FZeTaI/AAAAAAAAGA4/8QPyjT679Bg6ome8udb_7aDVEb7kqdevACLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B12.png"/></a></div>
<p id="imgCaption"> Remote Config personalization uses machine learning to help you optimize user experiences to achieve your goals </p>
<p>
We’ve also made several core improvements to Remote Config, including <strong>updating the parameter edit flow</strong> to make it easier to change targeting conditions and default values, and <strong>adding data type support</strong> to strengthen data validation and reduce the risk of pushing a bad value to your users. Finally, we’ve <strong>revamped the change history</strong> so you can clearly see when and how parameters were last changed. This will help you understand which app configuration changes correlate to changes in key metrics. Go to the Remote Config console to check out these updates and try personalization today!
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-egAAmuyPwyA/YYXJSZ1hj-I/AAAAAAAAGBA/o1T656zpaJY75RhKiBvZMEHOR4v47RhBwCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B13.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Targeting and data validation improvements in Remote Config" border="0" data-original-height="940" data-original-width="1600" src="https://1.bp.blogspot.com/-egAAmuyPwyA/YYXJSZ1hj-I/AAAAAAAAGBA/o1T656zpaJY75RhKiBvZMEHOR4v47RhBwCLcBGAsYHQ/s0/FB%2Brecap%2Bblog%2B13.png"/></a></div>
<p id="imgCaption"> Targeting and data validation improvements in Remote Config </p>
<h2>Your partner throughout your app’s journey</h2>
<p>
From building your app to optimizing it, we are your partner throughout the entire journey. We aim to make app development faster, easier, and streamline your path to success.You can rely on us to help you make your app the best it can be for users and your business. To get more insight into the announcements we shared above, be sure to <a href="https://firebase.google.com/summit">check out the technical sessions, codelabs, and demos from Firebase Summit</a>! If you want a sneak peek at what we’ll be launching in 2022, <a href="http://firebase.google.com/alpha">join our Alpha program</a>!
</p>
Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-41255938770414648492021-11-08T09:59:00.000-08:002021-11-08T09:59:30.881-08:00Automate your pre-release testing with the App Distribution REST API<meta name="twitter:image" content="https://1.bp.blogspot.com/-S_MseemRiGs/YYWmpflFPcI/AAAAAAAAF_U/VFb3ufSL4fsH02naiaXuA-xmVGKvzujQACLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BAutomate%2Byour%2Bpre-release%2Btesting%2Bwith%2Bthe%2BApp%2BDistribution%2BREST%2BAPI.gif">
<img style="display:none" src="https://1.bp.blogspot.com/-S_MseemRiGs/YYWmpflFPcI/AAAAAAAAF_U/VFb3ufSL4fsH02naiaXuA-xmVGKvzujQACLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BAutomate%2Byour%2Bpre-release%2Btesting%2Bwith%2Bthe%2BApp%2BDistribution%2BREST%2BAPI.gif">
<figure class="profile">
<div class="profile-picture">
<img style="margin: 0 0 0 0;" src="https://1.bp.blogspot.com/-aTjKAdQZmTQ/YJwdOl1oQvI/AAAAAAAAFic/VB4H4IdJDyMFln2bofxWDlSctwW6mbVCgCLcBGAsYHQ/s0/Liat%2BBerry.jpg" />
</div>
<figcaption>
<strong><div>Liat Berry</div>
</strong>
<em>Product Manager</em>
</figcaption>
</figure>
<figure class="profile">
<div class="profile-picture">
<img style="margin: 0 0 0 0;" src="https://1.bp.blogspot.com/-kZrbfTenUuw/YYWlQyMTJ0I/AAAAAAAAF_M/5ApPX6jxciwE4rja7RsxO_cFt0XvQW3iACLcBGAsYHQ/s0/Security%2BPhoto.jpeg" />
</div>
<figcaption>
<strong><div>Lee Kellogg</div>
</strong>
<em>Software Engineer</em>
</figcaption>
</figure>
<p>
Getting feedback on your app's releases before they reach the store is critical. <a href="https://firebase.google.com/products/app-distribution">App Distribution</a> makes it easy to share pre-release builds of your Android and iOS apps with your testers. You can distribute your apps to testers using the Firebase console, the Firebase CLI, or the App Distribution plugins for Gradle and fastlane.
</p>
<p>
We've also heard that you'd like to integrate your own tools directly with App Distribution, or implement custom pre-release testing workflows. That's where the <a href="https://firebase.google.com/docs/reference/app-distribution/rest">Firebase App Distribution REST API</a> comes in. With this API, you can build custom logic into your team's tools and services to add and remove testers, upload new app binaries, distribute your releases, update release notes, deleting releases, and more.
</p>
<p>
For example, let's say that your company gives all employees early access to the latest builds of your app. You also have a personnel management tool that automates the employee onboarding and offboarding process. Wouldn't it be nice if employee access was automatically granted and revoked as employees join and leave your company? With the REST API, you can build this functionality directly into your company's workflow.
</p>
<p>
Let's walk through the process to automatically grant and revoke access.
</p>
<h3>Authenticate with the API</h3>
<p>
To access the API, <a href="https://cloud.google.com/apis/docs/getting-started#enabling_apis">enable</a> the <a href="https://console.cloud.google.com/apis/library/firebaseappdistribution.googleapis.com?project=_">Firebase App Distribution API</a> for your project and choose a way to <a href="https://cloud.google.com/docs/authentication">authenticate</a> your integration. In this scenario, download a <a href="https://cloud.google.com/docs/authentication/production#create_service_account">service account key</a> and use <a href="https://github.com/google/oauth2l">oath2l</a> to get an access token:
</p>
<pre class="prettyprint">oauth2l fetch \
--credentials /path/to/service-account.json \
--scope https://www.googleapis.com/auth/cloud-platform
</pre>
<h3>Make HTTP requests to the API</h3>
<p>
Next, in hooks that are triggered when an employee joins or leaves the company, use the <a href="https://firebase.google.com/docs/reference/app-distribution/rest/v1/projects.testers/batchAdd">testers.batchAdd</a> and <a href="https://firebase.google.com/docs/reference/app-distribution/rest/v1/projects.testers/batchRemove">testers.batchRemove</a> endpoints to add or remove the employee as a tester in App Distribution using an HTTP request to the API. For example, here's how you can add a new tester using curl:
</p>
<pre class="prettyprint">SERVICE=https://firebaseappdistribution.googleapis.com
curl --request POST \
$SERVICE/v1/projects/[PROJECT_NUMBER]/testers:batchAdd \
--header 'Authorization: Bearer [ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"emails":["newemployee@company.com"]}'
</pre>
<p>
Let's say you periodically audit access to your pre-release apps to make sure that only authorized internal testers have access. To automate this audit, you can use the <a href="https://firebase.google.com/docs/reference/app-distribution/rest/v1/projects.testers/list">testers.list</a> endpoint to get the list of testers in your Firebase project. You can then write your own logic to compare that to your list of employee email addresses, or check the domains:
</p>
<pre class="prettyprint">curl \
$SERVICE/v1/projects/[PROJECT_NUMBER]/testers \
--header 'Authorization: Bearer [ACCESS_TOKEN]' \
--header 'Accept: application/json'
</pre>
<h3>Build your own custom workflow</h3>
<p>
Tester access and auditing is just one example of custom functionality you can build using the API. Other examples of functionality that you can build include keeping release notes in sync with your bug tracking system, fetching details about your most recent release, adding testers to releases from third-party tools, deleting releases in bulk, or fetching test certificate info for your Android app bundle releases.
</p>
<p>
App Distribution helps you gain confidence in your releases, and the REST API empowers you to integrate pre-release testing into your existing workflows. So get started with the API today! To learn more, and to try out the API using the embedded API Explorer, see the <a href="https://firebase.google.com/docs/reference/app-distribution/rest">Firebase App Distribution API</a> documentation.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-S_MseemRiGs/YYWmpflFPcI/AAAAAAAAF_U/VFb3ufSL4fsH02naiaXuA-xmVGKvzujQACLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BAutomate%2Byour%2Bpre-release%2Btesting%2Bwith%2Bthe%2BApp%2BDistribution%2BREST%2BAPI.gif" style="display: block; padding: 1em 0; text-align: center; "><img style="width:90%" alt="Try out the API using the API Explorer in the documentation" border="0" data-original-height="378" data-original-width="512" src="https://1.bp.blogspot.com/-S_MseemRiGs/YYWmpflFPcI/AAAAAAAAF_U/VFb3ufSL4fsH02naiaXuA-xmVGKvzujQACLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BAutomate%2Byour%2Bpre-release%2Btesting%2Bwith%2Bthe%2BApp%2BDistribution%2BREST%2BAPI.gif"/></a></div>
<p id="imgCaption"> Try out the API using the API Explorer in the documentation. </p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-12325387979228800412021-11-05T11:03:00.001-07:002021-11-05T11:03:41.539-07:00Improving the Google Analytics dashboard in Firebase<meta name="twitter:image" content="https://1.bp.blogspot.com/-eh1qGKBOwoA/YYQmsikS2bI/AAAAAAAAF90/ir_KJfpiDpQjMZBwvBMJ7kN0vRvFdvnPACLcBGAsYHQ/s0/image5.png">
<img style="display:none" src="https://1.bp.blogspot.com/-eh1qGKBOwoA/YYQmsikS2bI/AAAAAAAAF90/ir_KJfpiDpQjMZBwvBMJ7kN0vRvFdvnPACLcBGAsYHQ/s0/image5.png">
<figure class="profile">
<div class="profile-picture">
<img src="https://1.bp.blogspot.com/-FWlUEERjxRg/YYQ03lV4hFI/AAAAAAAAF-0/xFvyA-ko1BMOIdw_s44Y2BDOq4UlORO4ACLcBGAsYHQ/s0/BywoAB9b_400x400.jpeg"style="margin: 0px 0px 10px 0%;"/>
</div>
<figcaption>
<strong><div><a href="https://twitter.com/s_chande">
Sumit Chandel</a></div>
</strong>
<em> Developer Advocate</em>
</figcaption>
</figure>
<p>
If you’ve visited the Firebase console’s Analytics section recently, you might have noticed something new… an updated Analytics dashboard, a new Realtime view and a few other UI enhancements.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-eh1qGKBOwoA/YYQmsikS2bI/AAAAAAAAF90/ir_KJfpiDpQjMZBwvBMJ7kN0vRvFdvnPACLcBGAsYHQ/s0/image5.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="two screenshots of Google Analytics dashboard" border="0" data-original-height="1566" data-original-width="1999" src="https://1.bp.blogspot.com/-eh1qGKBOwoA/YYQmsikS2bI/AAAAAAAAF90/ir_KJfpiDpQjMZBwvBMJ7kN0vRvFdvnPACLcBGAsYHQ/s0/image5.png"/></a></div>
<p>
These new changes are part of our effort to improve the Google Analytics experience in Firebase, by providing access to some of the newest Google Analytics 4 innovations directly in the Firebase console.
</p>
<h2><strong>New Google Analytics 4 features available in the console</strong></h2>
<br>
<h3>The Dashboard</h3>
<p>
Firebase now shows a curated collection of Analytics cards that provide the same information as the previous dashboard, but presented more intuitively to get to key insights faster. This matches the ‘App Developer - Firebase’ collection in Google Analytics 4 - meaning you no longer need to switch to the Google Analytics interface to see this data. The cards are now organized by surfacing overview metrics first, followed by user engagement and retention cards, then monetization and user demographics.
</p>
<p>
The dashboard now also contains a lot of explorer cards that allow you to more easily drill-down into specifics for data represented by that card for more details - like the new <em>App Versions card</em> which provides a quick view into the number of users you have per app version, and a jumpoff link to see more data like engagement rates, revenue and conversions per app version as well.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-h8f_xxl9m3s/YYQnZBo5lkI/AAAAAAAAF-A/Mp_Lgayl8UY6GHFWzP-Wagwl_K8ZdY_7ACLcBGAsYHQ/s0/image3.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="two screenshots of Google Analytics dashboard with a 1 in a yellow circle and a 2 in a yellow circle" border="0" data-original-height="1175" data-original-width="1999" src="https://1.bp.blogspot.com/-h8f_xxl9m3s/YYQnZBo5lkI/AAAAAAAAF-A/Mp_Lgayl8UY6GHFWzP-Wagwl_K8ZdY_7ACLcBGAsYHQ/s0/image3.png"/></a></div>
<p>
The <em>Publisher card</em> is another example of providing a more natural flow to learn more about how different ad units are performing as well as the revenue they are generating.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/--qzI3LQJ2l8/YYQnBuabMeI/AAAAAAAAF94/PZgJVDMTi5c0wYMQzXNnaM-sGddfN0hLwCLcBGAsYHQ/s0/image6.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="two more screenshots of Google Analytics dashboard with a 1 in a yellow circle and a 2 in a yellow circle" border="0" data-original-height="1175" data-original-width="1999" src="https://1.bp.blogspot.com/--qzI3LQJ2l8/YYQnBuabMeI/AAAAAAAAF94/PZgJVDMTi5c0wYMQzXNnaM-sGddfN0hLwCLcBGAsYHQ/s0/image6.png"/></a></div>
<p>
Before adding this card to the dashboard, accessing this information would require digging into specific event reports, like the ad_impression event report to get out the ad unit performance or revenue data. Well, no need to go digging through various event reports anymore with this updated flow that should make accessing this information more convenient and intuitive.
</p>
<p>
Check out <a href="https://support.google.com/firebase/answer/11091821">this Google Analytics help center article for more information about the differences</a> between the new and older dashboard cards in the “Data cards before and after” section.
</p>
<br>
<h3>Comparisons</h3>
<p>
One feature that’s been around in Google Analytics 4 for a while but only just making an appearance in the Firebase console is the <em>Comparisons tool</em>, which replaces what was previously ‘Filters’. Similar to the Filters tool, with the Comparisons tool you can create comparison groups based on any custom or pre-defined Analytics dimensions or audiences. The advantage of the Comparisons tool is that you can create up to five comparison groups at once, and view and compare the Analytics data for each of these groups across all cards on the Analytics dashboard. For example, if you recently ran a promotional campaign offering 10% off in-app purchases to your top purchasers using <a href="https://firebase.google.com/docs/remote-config">Remote Config</a>, you can check to see the impact of that at a glance on metrics like user engagement and app revenue by comparing the top purchasers audience, your most engaged users audience, and all users by applying Comparisons in the dashboard.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-o2_wATNrFmI/YYQnpuMksbI/AAAAAAAAF-I/PWM3jMG4Sbg-IegeHvNr73JVzr-R3FfhQCLcBGAsYHQ/s0/image1.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Firebase Google Analytics overview dashboard" border="0" data-original-height="1440" data-original-width="1999" src="https://1.bp.blogspot.com/-o2_wATNrFmI/YYQnpuMksbI/AAAAAAAAF-I/PWM3jMG4Sbg-IegeHvNr73JVzr-R3FfhQCLcBGAsYHQ/s0/image1.png"/></a></div>
<p>
<br>Note to compare events or conversions as you would have done using Filters in the past, you can navigate to the Events or Conversions card from the dashboard to reveal a detailed report that you can then apply comparisons on.
</p>
<p>
<br>Check out <a href="https://support.google.com/analytics/answer/9269518?hl=en">this article</a> or <a href="https://www.youtube.com/watch?v=2F2XhgMt8Dg&t=404s">this video </a> that covers how to use the Comparison tool in more detail.
</p>
<br>
<h3>The Realtime view</h3>
<p>
The Realtime dashboard now shows the same views as in Google Analytics 4 and is great for, well, seeing events come in real-time from around the world. This can be really useful after just releasing a new feature, and seeing new events come in for the first time as it rolls out to your users. The updated dashboard contains new cards and new card capabilities, like the User Acquisition card that can be filtered by source, campaign, medium and platform, as well as the Users card that can now be filtered by audience.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-uqBOiwPFcU8/YYQn5q3XtdI/AAAAAAAAF-U/Ct6mqfdGnM4oGHsaqLGnTCFHKEN5CofVgCLcBGAsYHQ/s0/image2.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Google Analytics dashboard showing global audience" border="0" data-original-height="1440" data-original-width="1999" src="https://1.bp.blogspot.com/-uqBOiwPFcU8/YYQn5q3XtdI/AAAAAAAAF-U/Ct6mqfdGnM4oGHsaqLGnTCFHKEN5CofVgCLcBGAsYHQ/s0/image2.png"/></a></div>
<p>
One of the biggest benefits of this new change is the ability to use the Comparisons tool in the Realtime dashboard, too, so you can create and compare different groups over real-time app analytics data.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-RXmsJbZ3FlE/YYQoE_QideI/AAAAAAAAF-Y/H0WgsPymWpc9ks8Z8-ERKESt5W3B-04TQCLcBGAsYHQ/s0/image4.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="realtime overview in Google Analytics showing a blie, orange, and teal metric circle" border="0" data-original-height="1440" data-original-width="1999" src="https://1.bp.blogspot.com/-RXmsJbZ3FlE/YYQoE_QideI/AAAAAAAAF-Y/H0WgsPymWpc9ks8Z8-ERKESt5W3B-04TQCLcBGAsYHQ/s0/image4.png"/></a></div>
<br>
<h3>Google Analytics settings page</h3>
<p>
As part of this change, the Google Analytics settings page now links out to the Google Analytics console where you can modify any Analytics settings as you would previously in the <em>Firebase > Project Settings > Integration > Google Analytics</em> page. The Analytics Linking card however is still available and can be edited from within the Firebase console.
</p>
<p>
We invite you to take the updated Analytics dashboard in the Firebase console for a spin, and as always, let us know if you have any feedback or questions.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-1017004717679768192021-10-27T08:45:00.000-07:002021-10-27T08:45:35.782-07:00How to get better insight into push notification delivery<meta name="twitter:image" content="https://1.bp.blogspot.com/-Glicz9PxTgc/YXbhn-P-mVI/AAAAAAAAF64/Hoc7QxwaRYwrM7MjmnZlFDL4y8HPD8kUACLcBGAsYHQ/s0/Notification_Delivery_v1.png">
<img style="display:none" src="https://1.bp.blogspot.com/-Glicz9PxTgc/YXbhn-P-mVI/AAAAAAAAF64/Hoc7QxwaRYwrM7MjmnZlFDL4y8HPD8kUACLcBGAsYHQ/s0/Notification_Delivery_v1.png">
<figure class="profile">
<div class="profile-picture">
<img alt="Charlotte Liang" src="https://1.bp.blogspot.com/-n3MAgIcRk08/YXbgqxthOcI/AAAAAAAAF6w/kiWCMLjzEMQ0dfQKJjSyfYbIRmitC_ocgCLcBGAsYHQ/s0/Chen%2B%2528Charlotte%2529%2BLiang.jpeg" style="margin:0;" />
</div>
<figcaption>
<strong><div>
<a href="https://twitter.com/charlotteCLiang">Charlotte Liang</a> </div>
</strong>
<em>Software Engineer</em>
</figcaption>
</figure>
<figure class="profile">
<div class="profile-picture">
<img alt="Peter Friese"
src="https://1.bp.blogspot.com/-tWZr1igHXnU/X5icg0oh1TI/AAAAAAAAFRY/C4Gt4RREIIk5duHugCs5W13ut--zL7PzwCLcBGAsYHQ/s0/Peter%2BFriese.jpg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
<a href="https://twitter.com/peterfriese">Peter Friese</a> </div>
</strong>
<em>Developer Advocate </em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Glicz9PxTgc/YXbhn-P-mVI/AAAAAAAAF64/Hoc7QxwaRYwrM7MjmnZlFDL4y8HPD8kUACLcBGAsYHQ/s0/Notification_Delivery_v1.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Header image from blog post titled how to get better insight into push notification delivery" border="0" data-original-height="512" data-original-width="1024" src="https://1.bp.blogspot.com/-Glicz9PxTgc/YXbhn-P-mVI/AAAAAAAAF64/Hoc7QxwaRYwrM7MjmnZlFDL4y8HPD8kUACLcBGAsYHQ/s0/Notification_Delivery_v1.png"/></a></div>
<p>
<em>This article is part of the weekly learning pathways we’re releasing leading up to Firebase Summit. See the full pathway and register for the summit <a href="https://firebase.google.com/summit">here</a>.</em>
</p>
<p>
When you send a push notification to your users, things can go wrong in many places: the network might be down, the device might have performance issues or the send request might be invalid. And each platform has its own complexity so the challenges can keep adding up. All of this makes it difficult to know whether your notifications actually got delivered to users.
</p>
<p>
To get a better understanding of whether your notifications were delivered and where things might have gone wrong, you need one central place to collect all information and then run an analysis. This is where <a href="https://pantheon.corp.google.com/bigquery">BigQuery</a> can help. BigQuery, Google's solution for building data warehouses, gives you the ability to run queries and build custom dashboards that provide deep insights and actionable information.
</p>
<p>
With the Firebase Cloud Messaging Android SDK, you can <a href="https://firebase.google.com/docs/cloud-messaging/understand-delivery">log notification delivery data and export it to BigQuery</a>. We recently expanded the same support <a href="https://firebase.google.com/docs/cloud-messaging/understand-delivery?platform=ios#export-platform">for iOS</a> and <a href="https://firebase.google.com/docs/cloud-messaging/understand-delivery?platform=web#export-platform">the web</a>. In this article, we will walk you through the process of setting this up so you can better understand your delivery rate and identify ways to troubleshoot or improve it.
</p>
<h3>Enable BigQuery Export for your Firebase project</h3>
<p>
First, you need to enable BigQuery for your Firebase project. You can do this by navigating to the <strong>Firebase console</strong> > <strong>Project Settings</strong> > <strong>Integrations</strong>, and then click <strong>Link</strong> on the <strong>BigQuery</strong> card. It's worth noting that, by default, this integration uses the <a href="https://cloud.google.com/bigquery/docs/sandbox?_ga=2.267594439.-890369993.1627948303">BigQuery sandbox</a>. This lets you explore BigQuery capabilities at no cost, so you can evaluate if it fits your use case. After you link your Firebase project to BigQuery, Firebase will <a href="https://firebase.google.com/docs/cloud-messaging/understand-delivery?platform=ios#what-data-exported">export your data</a> to BigQuery. The initial propagation of data might take up to 48 hours to complete.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-SWLDxxgb10k/YXbjIuU6m7I/AAAAAAAAF7A/JrGzUiEgch8q6xXf2gXCqYRUmT1exQ22gCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B3_1.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:80%" alt="You can do this by navigating to the Firebase console > Project Settings > Integrations, and then click Link on the BigQuery card" border="0" data-original-height="229" data-original-width="253" src="https://1.bp.blogspot.com/-SWLDxxgb10k/YXbjIuU6m7I/AAAAAAAAF7A/JrGzUiEgch8q6xXf2gXCqYRUmT1exQ22gCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B3_1.png"/></a></div>
<p>
Once the data is successfully exported, you should be able to see a <code>data</code> table created under your project’s <code>firebase_messaging</code> tab in the <a href="https://console.cloud.google.com/bigquery">BigQuery console</a>.
</p>
<p>
To collect Notification Delivery data, you need to enable logging on the client side. In the next step, we're going to set up the iOS client and start logging some data to BigQuery.
</p>
<h3>iOS Delivery Data Logging</h3>
<p>
With the Firebase Messaging iOS SDK <a href="https://firebase.google.com/support/release-notes/ios#version_860_-_august_17_2021">8.6.0</a> or higher, you can now enable notification delivery logging in your app that exports to BigQuery by calling a new API we recently added. You will need to log alert and background notifications separately (this is only required for Apple's platforms).
</p>
<p>
<strong>Alert notifications and Notification Service Extension</strong>
</p>
<p>
To log alert notifications delivery, you first need to add a <a href="https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension?language=objc">Notification Service Extension</a> to your project in Xcode. The Notification Service Extension lets you customize the content of notifications before they become visible to users. Apple’s developer documentation has more details about <a href="https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications?language=objc">how to add a service extension to your project</a>.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-gLlwBKBGNmk/YXbjnWDP_RI/AAAAAAAAF7I/zNzTA1odFCoHCAqe1ZbY6uw_6JxFxHXcgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B3_2.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="To log alert notifications delivery, you first need to add a Notification Service Extension to your project in Xcode" border="0" data-original-height="363" data-original-width="512" src="https://1.bp.blogspot.com/-gLlwBKBGNmk/YXbjnWDP_RI/AAAAAAAAF7I/zNzTA1odFCoHCAqe1ZbY6uw_6JxFxHXcgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B3_2.png"/></a></div>
<p>
After adding the Notification Service Extension to your project, find the <code>NotificationService didReceiveNotificationRequest:withContentHandler:</code> method inside the service extension target. This is where you will add code to enable logging.
</p>
<p>
In Firebase <a href="https://firebase.google.com/support/release-notes/ios#version_860_-_august_17_2021">8.6.0</a>, We have introduced a new method to the Firebase Messaging API: the<em> delivery data export</em> API <code>FIRMessagingExtensionHelper exportDeliveryMetricsToBigQueryWithMessageInfo:</code>. Logging is disabled by default, so you will need to explicitly enable it by calling this API inside the Notification Service Extension.
</p>
<pre class="prettyprint"> override func didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent)
-> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy()
as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.title = "\(bestAttemptContent.title) 👩🏻💻"
// Log Delivery signals and export to BigQuery.
Messaging.serviceExtension()
.exportDeliveryMetricsToBigQuery(withMessageInfo: request.content.userInfo)
// Add image, call this last to finish with the content handler.
Messaging.serviceExtension()
.populateNotificationContent(bestAttemptContent, withContentHandler: contentHandler)
}
}
</pre>
<p>
Note that, if you use the Firebase Cloud Messaging SDK to add an image to your notification, you need to make sure to call the deliver data export API before calling <code>Messaging.serviceExtension().populateNotificationContent(_:withContentHandler)</code>, as shown in the code snippet above.
</p>
<p>
The Apple system only passes the notification to the service extension if the notification payload contains the key <code><a href="https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications?language=objc">"mutable-content" :1</a></code>, so make sure you specify this key if you use the HTTP v1 API. If you use the Firebase console to send notifications, <code>"mutable-content" :1</code> will be set automatically.
<p>
<strong>Background notifications</strong>
</p>
<p>
<a href="https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app?language=objc">Background notifications</a> are hidden messages that allow your app to wake up and update data in the background. To enable <em>delivery data export</em> for these kinds of notifications, you will need to implement the <code><a href="https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application?language=objc">application:didReceiveRemoteNotification:fetchCompletionHandler:</a></code> method and call <code>exportDeliveryMetricsToBigQueryWithMessageInfo:</code> method as shown below:
</p>
<pre class="prettyprint">// For background notifications, call the API inside the UIApplicationDelegate method:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
Messaging.extensionHelper().exportDeliveryMetricsToBigQuery(withMessageInfo:userInfo)
}
</pre>
<p>
Make sure to include <code><a href="https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc">"content-available":1</a></code> to specify it’s a background notification when you use the HTTP v1 API to send the notification.
<h3>Web Delivery Data Logging (Alpha)</h3>
<p>
Notification Delivery Logging is newly available on the web for Firebase JS SDK versions <a href="https://firebase.google.com/support/release-notes/js#cloud-messaging_1">9.0.0</a> and newer. To enable delivery data export, all you need to do is to enable the flag on a service worker as shown below. This is handled similarly to Android.
</p>
<pre class="prettyprint">// userConsent holds the decision of the user to give big query export consent.
const userConsent = ...;
const messaging = getMessagingInSw(app);
experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, userConsent)
</pre>
<h3>Android Delivery Data Logging</h3>
<p>
Notification Delivery Logging has been supported on Android since Firebase SDKs version 20.1.0 or higher. On Android, you can call the delivery data logging API to enable data export for both display and data messages like this:
</p>
<pre class="prettyprint"> FirebaseMessaging.getInstance().setDeliveryMetricsExportToBigQuery(true)
</pre>
<h3>Turning it off again</h3>
<p>
By default, Notification Delivery Logging is disabled on all three platforms, and will only be activated once you call the API to enable it for the particular platform your app is running on. You can also deactivate the BigQuery export any time by <a href="https://support.google.com/firebase/answer/6318765#unlink&zippy=%2Cin-this-article">unlinking your project</a> in the Firebase console.
</p>
<p>
<strong>Results on BigQuery</strong>
</p>
<p>
Once you have successfully logged some data you will see this data in the <a href="https://pantheon.corp.google.com/bigquery">BigQuery console</a>. Keep in mind that the data is regularly pushed from Firebase to BigQuery and the daily propagation might take some time (up to a couple of hours, depending on the amount of data) to complete.
</p>
<p>
BigQuery data also includes customized analytics labels that help you to create custom queries. Here’s a preview what type of data you can get from the iOS platform:
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-daGR4AWpNsE/YXbkuuA0_DI/AAAAAAAAF7Q/xJpfDVFs3m4W_LyhM036eGzPlceovuHkQCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B3_3.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Here’s a preview what type of data you can get from the iOS platform" border="0" data-original-height="163" data-original-width="512" src="https://1.bp.blogspot.com/-daGR4AWpNsE/YXbkuuA0_DI/AAAAAAAAF7Q/xJpfDVFs3m4W_LyhM036eGzPlceovuHkQCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B3_3.png"/></a></div>
<p>
With the delivery data on BigQuery, you can now run custom queries or build a customized dashboard based on your needs. It provides detailed information about your campaign, including message identifier, message type, SDK platform and timestamp so you can get a lot of useful information helping you identify if the message was sent as expected. You can also segment the data based on your custom analytics labels. And if you are interested in getting additional aggregate information about message delivery on Android, check out <a href="https://medium.com/firebase-developers/what-is-fcm-aggregated-delivery-data-d6d68396b83b">this Medium post</a> to find out how to use FCM Aggregation API for advanced data analysis.
</p>
<h3>Make the most of Firebase</h3>
<p>
<a href="https://firebase.google.com/learn/pathways/firebase-user-engagement">View the full learning pathway</a> on FCM message delivery for additional codelabs, videos and articles. And don’t forget to <a href="https://firebase.google.com/summit">register for Firebase Summit</a> and join us on November 10th to learn how Firebase can help you accelerate your app development, release with confidence and scale with ease!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-67223782028193630202021-10-20T08:45:00.001-07:002022-03-09T12:08:09.484-08:00Pinpointing API performance issues with Custom URL Patterns<meta name="twitter:image" content="https://1.bp.blogspot.com/-EOvhMwUbl3w/YW3d3uSV3wI/AAAAAAAAF5w/mP3Q_9aA89Y8_st_po2CKQSnnr07XxGvwCLcBGAsYHQ/s0/API_Perf_Issues_v3.png">
<img style="display:none" src="https://1.bp.blogspot.com/-EOvhMwUbl3w/YW3d3uSV3wI/AAAAAAAAF5w/mP3Q_9aA89Y8_st_po2CKQSnnr07XxGvwCLcBGAsYHQ/s0/API_Perf_Issues_v3.png">
<figure class="profile">
<div class="profile-picture">
<img alt="Ibrahim Ulukaya" src="https://1.bp.blogspot.com/-O9V7t2KY9pM/YW3dtcSvBBI/AAAAAAAAF5s/XnSoH20uP5obAoyE9xo1ZOZ56J2ftK4lgCLcBGAsYHQ/s0/Ibrahim%2BUlukaya.jpeg" style="margin:0;" />
</div>
<figcaption>
<strong><div>
Ibrahim Ulukaya</div>
</strong>
<em>Developer Advocate</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-EOvhMwUbl3w/YW3d3uSV3wI/AAAAAAAAF5w/mP3Q_9aA89Y8_st_po2CKQSnnr07XxGvwCLcBGAsYHQ/s0/API_Perf_Issues_v3.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="blog header demonstrating Pinpointing API performance issues with custom URL patterns" border="0" data-original-height="512" data-original-width="1024" src="https://1.bp.blogspot.com/-EOvhMwUbl3w/YW3d3uSV3wI/AAAAAAAAF5w/mP3Q_9aA89Y8_st_po2CKQSnnr07XxGvwCLcBGAsYHQ/s0/API_Perf_Issues_v3.png"/></a></div>
<p>
<em>This article is part of the weekly learning pathways we’re releasing leading up to Firebase Summit. See the full pathway and register for the summit <a href="https://firebase.google.com/summit">here</a>.</em>
</p>
<p>
Apps and games have evolved rapidly in recent years, and user expectations for high performing apps have increased right alongside them. Today’s users don’t just demand speed and performance — they reward it. A <a href="https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/mobile-page-speed-data/">2019 study</a> found that retail sites saw 8% more conversions when they reduced their mobile site load times by one-tenth of a second. And travel sites boosted conversions by just over 10%.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-vue6NGtyvos/YW37gy7PhyI/AAAAAAAAF54/8-d7YCCfqp8dl8difv0ldCpMwNy8X7YaQCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_2.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="A 2019 study found that retail sites saw 8% more conversions when they reduced their mobile site load times by one-tenth of a second. And travel sites boosted conversions by just over 10%" border="0" data-original-height="500" data-original-width="1600" src="https://1.bp.blogspot.com/-vue6NGtyvos/YW37gy7PhyI/AAAAAAAAF54/8-d7YCCfqp8dl8difv0ldCpMwNy8X7YaQCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_2.png"/></a></div>
<p>
Pinpointing an app’s performance issues can be challenging, especially when the culprit is slow network requests from your dependencies or even your own server.
</p>
<p>
This is where network analysis from Firebase Performance Monitoring can help. Firebase Performance Monitoring helps you understand your app’s performance from the user’s perspective in near real time. You can analyze the performance of each module of your app by monitoring response times, success rates, and payload sizes of your most critical network requests.
</p>
<p>
Let’s look at how we were able to spot performance pitfalls in BingoBlast - Firebase's very own demo app.
</p>
<h3>Automatic aggregation</h3>
<p>
Out-of-the-box, Firebase Performance Monitoring measures each network request that is sent from your app. To surface the most important trends from the vast number of URLs, Firebase automatically aggregates data for similar network requests to representative <a href="https://firebase.google.com/docs/perf-mon/network-traces#url-patterns">URL patterns</a>. Furthermore, this aggregation removes all PII (Personal Identifiable Information) such as home address, username, and password so that developers don't need to worry about leaking user information.
</p>
<p>
Firebase displays all URL patterns (including custom URL patterns) and their aggregated data in the Network requests subtab of the traces table, which is the lower half of the <em><a href="https://console.firebase.google.com/project/_/performance">Performance dashboard</a></em>.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-gp4bW3lke1Q/YW386J3Q2hI/AAAAAAAAF6A/P7O4sVOLCO8t6bQMl1bmxRlg0vXejNWtwCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_3.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="BingoBlast Auto Aggregate Data
" border="0" data-original-height="212" data-original-width="512" src="https://1.bp.blogspot.com/-gp4bW3lke1Q/YW386J3Q2hI/AAAAAAAAF6A/P7O4sVOLCO8t6bQMl1bmxRlg0vXejNWtwCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_3.png"/></a></div>
<p id="imgCaption">BingoBlast Auto Aggregate Data.</p>
<p>
By just integrating Firebase Performance Monitoring into your app, you can quickly see the slowest network requests your app is making and how that performance has changed over time.
</p>
<p>
For BingoBlast, our traces table shows that some network requests have substantial slowdowns in their response time over the past several days, signaling that there might already be issues needing our attention.
</p>
<p>
Although Firebase does a great job at automatically generating URL patterns, at times the specific pattern you're interested in might be hidden under an automated pattern. In those situations, you can create <em>custom</em> URL patterns to monitor specific URL patterns that Firebase isn't capturing with its derived <a href="https://firebase.google.com/docs/perf-mon/network-traces#automatic-url-patterns">automatic URL pattern matching</a>.
</p>
<h3>Custom URL patterns</h3>
<p>
Custom URL patterns let you specify the patterns that will take precedence over the automatic URL patterns. With custom URL patterns, you can:
</p>
<ul>
<li>Track a more specific pattern that you're interested in which might normally be aggregated within a broader pattern.
<li>Aggregate a group of related URL patterns that might not have been aggregated automatically.
</li>
</ul>
<p>
A custom URL pattern consists of the hostname followed by path segments. Subdomains and path segments can be replaced with a <code>*</code> to represent matching with any string.
</p>
<p>
If a request's URL matches more than one custom URL pattern, Firebase Performance Monitoring maps the request to the most specific custom URL pattern based on left-to-right specificity. See the <a href="https://firebase.google.com/docs/perf-mon/custom-url-patterns#custom-url-pattern-matching">documentation</a> for the full details and syntax available.
</p>
<p>
For example, suppose you configure two custom URL patterns:
</p>
<pre class="prettyprint">example.com/books/*
example.com/*/dog
</pre>
<p>
A request to <code>example.com/books/dog</code> will match against <code>example.com/books/*</code> because <code>book</code> is more specific than <code>*</code>.
</p>
<h3>Tracking a more specific pattern</h3>
<p>
To show how custom URL patterns can be helpful, let's look closer at the data from BingoBlast. Let's say that we're worried that an important configuration API request (<code>api.redhotlabs.com/1.2/config.get</code>) might be causing issues in BingoBlast. But, we're unable to find it in our list of automatic network URL patterns. In this case, Firebase Performance Monitoring has aggregated the configuration API request along with a few other API requests into the <code>api.redhotlabs.com/1.2/*</code> URL pattern.
</p>
<p>
To get better insight into any performance issues this API call might be causing, let's use a custom URL pattern for this specific request.
</p>
<p>
To do this, we just click the <strong><em>Create custom URL pattern</em></strong> button in the traces table, then enter <code>api.redhotlabs.com/1.2/config.get</code> into the dialog. After the new pattern is created, the traces table will start displaying the new custom URL pattern based on new data.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-zto6bKTbSds/YW3-Ai1GApI/AAAAAAAAF6I/hKzuCB-FbochzgVId0PFonqF5_841Q1TgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_4.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Creating a new custom URL pattern" border="0" data-original-height="491" data-original-width="512" src="https://1.bp.blogspot.com/-zto6bKTbSds/YW3-Ai1GApI/AAAAAAAAF6I/hKzuCB-FbochzgVId0PFonqF5_841Q1TgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_4.png"/></a></div>
<p id="imgCaption">Creating a new custom URL pattern.</p>
<p>
Since this is an important API request and we want to track our improvements to it over time, we can add metrics (like response time) for this new custom URL pattern to our metrics board at the top of the <em>Performance</em> dashboard page. These metrics cards are a great way to provide a quick overview of your most important metrics.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-FGoyi5ekw64/YW3-j4oiGzI/AAAAAAAAF6Q/jbtu5AqwH98r_gd0eVTevflR4KsavZLmACLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_5.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Pin your most important metrics to the top of your dashboard" border="0" data-original-height="247" data-original-width="512" src="https://1.bp.blogspot.com/-FGoyi5ekw64/YW3-j4oiGzI/AAAAAAAAF6Q/jbtu5AqwH98r_gd0eVTevflR4KsavZLmACLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_5.png"/></a></div>
<p id="imgCaption">Pin your most important metrics to the top of your dashboard.</p>
<p>
With <code>api.redhotlabs.com/1.2/config.get</code> extracted as its own URL pattern, it's easier to monitor for any unwanted changes in the performance of these requests. We can then take action, like removing the request from the app's critical path or recommending improvements for the backend implementation.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Eyy0G21-yiM/YW3--miiweI/AAAAAAAAF6Y/ewqY2Nyq5YQo1LbBcHCEhs7p_gIDUfpXgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_6.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" data-original-height="182" data-original-width="512" src="https://1.bp.blogspot.com/-Eyy0G21-yiM/YW3--miiweI/AAAAAAAAF6Y/ewqY2Nyq5YQo1LbBcHCEhs7p_gIDUfpXgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_6.png"/></a></div>
<p id="imgCaption"><em>Newly added <code>api.redhotlabs.com/1.2/config.get</code> custom URL pattern</em>.</p>
<h3>Grouping related URL patterns</h3>
<p>
On the other hand, we sometimes want to group related URLs into a single URL pattern. In BingoBlast, we have included a library that plays a short video. However, we noticed that our traces table is showing many separate URL patterns to different <code>googlevideo.com</code> subdomains.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Qbn2gUw8P_4/YW3_Xm4Nl-I/AAAAAAAAF6g/ZOs3R4CnZnAkV0ZyrzZ_tNx7KgL4rDtXgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_7.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Overly precise automated URL patterns for googlevideo.com subdomains" border="0" data-original-height="152" data-original-width="512" src="https://1.bp.blogspot.com/-Qbn2gUw8P_4/YW3_Xm4Nl-I/AAAAAAAAF6g/ZOs3R4CnZnAkV0ZyrzZ_tNx7KgL4rDtXgCLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_7.png"/></a></div>
<p id="imgCaption">Overly precise automated URL patterns for googlevideo.com subdomains.</p>
<p>
Since we're more concerned about the overall performance of the video requests, as opposed to which specific subdomain they're from, we can create a custom URL pattern <code>*.googlevideo.com/**</code> to aggregate all these URLs into one pattern. This makes it easy to understand the performance for the video and, as a bonus, makes our traces table more tidy!
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-bv54Nnm2PZ8/YW3_-xcwl7I/AAAAAAAAF6o/1FMIaKVfVScTt_8bI1L7Jxs6Z4mkLzMcACLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_8.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Newly aggregated data for the custom URL pattern for googlevideo.com subdomains" border="0" data-original-height="96" data-original-width="512" src="https://1.bp.blogspot.com/-bv54Nnm2PZ8/YW3_-xcwl7I/AAAAAAAAF6o/1FMIaKVfVScTt_8bI1L7Jxs6Z4mkLzMcACLcBGAsYHQ/s0/FB%2BBLOG%2Bweek%2B2_8.png"/></a></div>
<p id="imgCaption">Newly aggregated data for the custom URL pattern for googlevideo.com subdomains.</p>
<p>
Firebase Performance Monitoring provides a wealth of data on how your users experience your app. By leveraging Firebase’s out-of-the-box automatic URL patterns and tailoring your dashboard with custom URL patterns you’re most interested in, you can easily pinpoint slow performance areas in your apps and quickly boost your app’s responsiveness.
</p>
<h3>Make the most of Firebase</h3>
<p>
<a href="https://firebase.google.com/learn/pathways/firebase-apps">View the full learning pathway</a> for additional codelabs, videos and articles on creating fast and stable apps. And don’t forget to <a href="https://firebase.google.com/summit">register for Firebase Summit</a>, happening November 10th to learn how Firebase can help you accelerate your app development, release with confidence, and scale with ease!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-48333873566895667972021-10-12T18:00:00.016-07:002021-11-04T13:07:41.483-07:00Protecting your backends with Firebase App Check<meta name="twitter:image" content="https://1.bp.blogspot.com/-sKK0sEWdqGc/YWXEwC3vP_I/AAAAAAAAF5I/X5wPonrxM3sOa7scoA1BCTDFgnfe5oMdwCLcBGAsYHQ/s0/FB%2BBLOG%2Bprotecting%2Byour%2Bbackends%2Bwith%2Bapp%2Bcheck.png">
<img style="display:none" src="https://1.bp.blogspot.com/-sKK0sEWdqGc/YWXEwC3vP_I/AAAAAAAAF5I/X5wPonrxM3sOa7scoA1BCTDFgnfe5oMdwCLcBGAsYHQ/s0/FB%2BBLOG%2Bprotecting%2Byour%2Bbackends%2Bwith%2Bapp%2Bcheck.png">
<figure class="profile">
<div class="profile-picture">
<img alt="Alex Volkovitsky"
src="https://1.bp.blogspot.com/-4jt85G63Gu0/YWW7utlBDKI/AAAAAAAAF44/9AQ7EB7XOhArd1PoVWyfTt4mB9T-3LF0ACLcBGAsYHQ/s0/Alex%2BVolkovitsky.jpeg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Alex Volkovitsky</div>
</strong>
<em>Software Engineer </em>
</figcaption>
</figure>
<figure class="profile">
<div class="profile-picture">
<img alt="Victor Fan"
src="https://1.bp.blogspot.com/-xUKqKVtTjUw/YWbpRLQ1tAI/AAAAAAAAF5Q/hk04FLo4xVkqCYwQtzyGfOuL3hLWKph7wCLcBGAsYHQ/s0/unnamed-1.jpg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Victor Fan</div>
</strong>
<em>Software Engineer </em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-RX8QhKwoD8A/YWjLOqUeI6I/AAAAAAAAF5Y/pTmyKbmAYUwkn2TpzVd4c5gzeD8T6LuTgCLcBGAsYHQ/s0/Firebase-Summit-21-Week1-Build%2B%25281%2529.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="header image that says Firebase Summit 2021" border="0" data-original-height="512" data-original-width="1024" src="https://1.bp.blogspot.com/-RX8QhKwoD8A/YWjLOqUeI6I/AAAAAAAAF5Y/pTmyKbmAYUwkn2TpzVd4c5gzeD8T6LuTgCLcBGAsYHQ/s0/Firebase-Summit-21-Week1-Build%2B%25281%2529.png"/></a></div>
<p>
<em>This article is part of the weekly learning pathways we’re releasing leading up to Firebase Summit. See the full pathway and register for the summit <a href="https://firebase.google.com/summit">here</a>. </em>
</p>
<p>
Earlier this year at Google I/O, we announced <a href="https://firebase.google.com/docs/app-check">Firebase App Check</a>, Firebase's new platform for protecting your Firebase APIs from abuse. Not only can App Check protect hosted APIs (such as Cloud Storage for Firebase, Firebase Realtime Database, and others), it can also be used to protect your own backend resources, whether they are run in a managed environment such as Cloud Run or hosted on your own infrastructure.
</p>
<p>
To prevent abuse, your public APIs should verify that the calling application is authorized to make requests, regardless of whether a user credential is present or not. Imagine you run a backend which provides the API for a free mobile app; your app might be funded with ads, so you should ensure that all requests originate from your app—and not someone else's app!
</p>
<p>
To protect your backend with App Check, your apps should send an App Check token with every request. Apps built with Firebase SDKs and with App Check functionalities properly configured will automatically obtain and refresh App Check tokens for you. They will also automatically send those tokens along with every request to supported Firebase services such as Cloud Storage for Firebase, Cloud Functions for Firebase, and Firebase Realtime Database. These services will also automatically verify those tokens for you.
</p>
<p>
On the other hand, if you run your services on your own infrastructure, <em>you</em> are responsible for making sure that:
</p>
<ul>
<li>Your apps send an App Check token with every request to your services. Learn how to do this for your <a href="https://firebase.google.com/docs/app-check/android/custom-resource">Android</a>, <a href="https://firebase.google.com/docs/app-check/ios/custom-resource">iOS</a>, and <a href="https://firebase.google.com/docs/app-check/web/custom-resource">web</a> apps.
<li>Your services validate App Check tokens in your backend code. In this blog post, we're going to show you how to do this in several different contexts.
</li>
</ul>
<h2>Verifying App Check tokens in a Node.js backend</h2>
<p>
In Node.js backends running in trusted environments, such as Cloud Run, Cloud Functions, or your own server, it is common practice to use middleware modules to integrate cross-cutting concerns like this. Here's a code snippet that defines an Express.js middleware layer that verifies the App Check token using the Firebase Admin SDK:
</p>
<pre class="prettyprint">const express = require('express');
const firebaseAdmin = require('firebase-admin');
const app = express();
firebaseAdmin.initializeApp();
const appCheckVerification = async (req, res, next) => {
const appCheckClaims =
await verifyAppCheckToken(req.header('X-Firebase-AppCheck'));
if (!appCheckClaims) {
res.status(401);
return next('Unauthorized');
}
next();
};
const verifyAppCheckToken = async (appCheckToken) => {
if (!appCheckToken) {
return null;
}
try {
return firebaseAdmin.appCheck().verifyToken(appCheckToken);
} catch (err) {
return null;
}
};
app.get('/yourApiEndpoint', [appCheckVerification], (req, res) => {
// Handle request.
});
</pre>
<p>
For more details, check out our <a href="https://firebase.google.com/docs/app-check/web/custom-resource#verify_tokens_on_the_backend">documentation</a>.
</p>
<h2>Verifying App Check tokens in other backend resources</h2>
<p>
App Check tokens are implemented as JSON Web Tokens (JWT) as specified by <a href="https://datatracker.ietf.org/doc/html/rfc7519">RFC 7519</a>. This means they are signed JSON objects. To assert that an App Check token is legitimate, you must perform the following steps:
</p>
<ol>
<li>Obtain the Firebase App Check public JSON Web Key (JWK) Set (as specified by <a href="https://datatracker.ietf.org/doc/html/rfc7517">RFC 7517</a>) from our JWKS endpoint (<code><a href="https://firebaseappcheck.googleapis.com/v1beta/jwks">https://firebaseappcheck.googleapis.com/v1beta/jwks</a></code>).
<li>Verify the App Check token's signature to ensure it is legitimate.
<li>Ensure that the token's header uses the algorithm <code>RS256</code>.
<li>Ensure that the token's header has type <code>JWT</code>.
<li>Ensure that the token is issued by Firebase App Check under your project.
<li>Ensure that the token has not expired.
<li>Ensure that the token's audience matches your project.
<li>If desired, you can also check that the token's subject matches your app's App ID.
</li>
</ol>
<p>
The following example performs the necessary steps in Ruby using the <a href="https://github.com/jwt/ruby-jwt">jwt</a> gem as a Rack middleware layer. Many languages have similar <a href="https://datatracker.ietf.org/group/jose/documents/">JSON Object Signing and Encryption</a> (JOSE) libraries that you can use for this purpose.
</p>
<pre class="prettyprint">require 'json'
require 'jwt'
require 'net/http'
require 'uri'
class AppCheckVerification
def initialize(app, options = {})
@app = app
@project_number = options[:project_number]
end
def call(env)
app_id = verify(env['HTTP_X_FIREBASE_APPCHECK'])
return [401, { 'Content-Type' => 'text/plain' }, ['Unauthenticated']] unless app_id
env['firebase.app'] = app_id
@app.call(env)
end
def verify(token)
return unless token
# 1. Obtain the Firebase App Check Public Keys
# Note: It is not recommended to hard code these keys as they rotate,
# but you should cache them for up to 6 hours.
uri = URI('https://firebaseappcheck.googleapis.com/v1beta/jwks')
jwks = JSON(Net::HTTP.get(uri))
# 2. Verify the signature on the App Check token
payload, header = JWT.decode(token, nil, true, jwks: jwks, algorithms: 'RS256')
# 3. Ensure the token's header uses the algorithm RS256
return unless header['alg'] == 'RS256'
# 4. Ensure the token's header has type JWT
return unless header['typ'] == 'JWT'
# 5. Ensure the token is issued by App Check
return unless payload['iss'] == "https://firebaseappcheck.googleapis.com/#{@project_number}"
# 6. Ensure the token is not expired
return unless payload['exp'] > Time.new.to_i
# 7. Ensure the token's audience matches your project
return unless payload['aud'].include? "projects/#{@project_number}"
# 8. The token's subject will be the app ID, you may optionally filter against
# an allow list
payload['sub']
rescue
end
end
class Application
def call(env)
[200, { 'Content-Type' => 'text/plain' }, ["Hello app #{env['firebase.app']}"]]
end
end
use AppCheckVerification, project_number: 1234567890
run Application.new
</pre>
<h2>Verifying App Check tokens at the edge</h2>
<p>
If your application uses content delivery networks (CDNs) to cache content closer to your users, you can use App Check to filter out abusive traffic at the edge. Since the Firebase Admin SDK's App Check functionalities are currently only available in Node.js and not all CDN providers support the Node.js runtime, you may need to verify App Check tokens in another runtime supported by the CDN. For this use case, you can adapt the following example for CloudFlare workers:
</p>
<pre class="prettyprint">import { JWK, JWS } from "node-jose";
// Specify your project number to ensure only your apps make requests to your CDN
const PROJECT_NUMBER = 1234567890;
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
});
async function handleRequest(request) {
const appCheckToken = request.headers.get('X-Firebase-AppCheck');
const appId = await verifyAppCheckToken(appCheckToken);
if (!appId) {
return new Response("Unauthorized", { status: 401 });
}
return new Response(`Hello app ${appId}`, {
headers: { "content-type": "text/plain" }
});
}
async function verifyAppCheckToken(encodedToken) {
if (!encodedToken) {
return null;
}
// 1. Obtain the Firebase App Check Public Keys
// Note: It is not recommended to hard code these keys as they rotate,
// but you should cache them for up to 6 hours.
const jwks = await fetch("https://firebaseappcheck.googleapis.com/v1beta/jwks", {
headers: {
"content-type": "application/json;charset=UTF-8",
}
});
// 2. Verify the signature on the App Check token
const keystore = await JWK.asKeyStore(await jwks.json());
const token = await JWS.createVerify(keystore).verify(encodedToken);
// 3. Ensure the token's header uses the algorithm RS256
if (token.header["alg"] !== "RS256") {
return null;
}
// 4. Ensure the token's header has type JWT
if (token.header["typ"] !== "JWT") {
return null;
}
const payload = JSON.parse(token.payload.toString());
// 5. Ensure the token is issued by App Check
if (payload["iss"] !== `https://firebaseappcheck.googleapis.com/${PROJECT_NUMBER}`) {
return null;
}
// 6. Ensure the token is not expired
if (Date.now() > payload["exp"] * 1000) {
return null;
}
// 7. Ensure the token's audience matches your project
if (!payload["aud"].includes(`projects/${PROJECT_NUMBER}`)) {
return null;
}
// 8. The token's subject will be the app ID, you may optionally filter against
// an allow list
return payload["sub"];
}
</pre>
<h2>Verifying App Check tokens in Apigee</h2>
<p>
<a href="https://cloud.google.com/apigee">Apigee</a> is Google Cloud's comprehensive API management platform for your APIs. In Apigee, you can easily implement a policy for your API Proxy that checks for the presence and validity of Firebase App Check tokens for all your incoming requests.
</p>
<p>
In the following example, we will check for the presence of the Firebase App Check token in the request header <code>X-Firebase-AppCheck</code>, ensure that it is valid, and verify that it was issued by the correct project.
</p>
<p>
First, in your API Proxy, add a <strong><a href="https://docs.apigee.com/api-platform/reference/policies/verify-jwt-policy">Verify JWT</a></strong> policy; you can enter any <em>Display Name</em>.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-sKK0sEWdqGc/YWXEwC3vP_I/AAAAAAAAF5I/X5wPonrxM3sOa7scoA1BCTDFgnfe5oMdwCLcBGAsYHQ/s0/FB%2BBLOG%2Bprotecting%2Byour%2Bbackends%2Bwith%2Bapp%2Bcheck.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="in your API Proxy, add a Verify JWT policy; you can enter any Display Name." border="0" data-original-height="337" data-original-width="512" src="https://1.bp.blogspot.com/-sKK0sEWdqGc/YWXEwC3vP_I/AAAAAAAAF5I/X5wPonrxM3sOa7scoA1BCTDFgnfe5oMdwCLcBGAsYHQ/s0/FB%2BBLOG%2Bprotecting%2Byour%2Bbackends%2Bwith%2Bapp%2Bcheck.png"/></a></div>
<p>
Similar to the examples we have seen so far, you will need to perform all of the following steps in this policy:
</p>
<ul>
<li>Extract the Firebase App Check token from the client request; we highly recommend passing it as a header, such as <code>X-Firebase-AppCheck</code>, and use <code>request.headers.X-Firebase-AppCheck</code> as the <code><Source></code>.
<li>Provide our Public JWKS (as specified by <a href="https://datatracker.ietf.org/doc/html/rfc7517">RFC 7517</a>) endpoint: <code>https://firebaseappcheck.googleapis.com/v1beta/jwks</code>.
<li>Ensure that the <code><Algorithm></code> is set to <code>RS256</code>.
<li>Ensure that the <code><Audience></code> contains <code>projects/{project_number}</code>. Here, the <code>{project_number}</code> is the project number of your Firebase project that issued the Firebase App Check token (without the braces).
<li>Ensure that the <code><Issuer></code> is equal to <code>https://firebaseappcheck.googleapis.com/{project_number}</code>; again, ensure that the <code>{project_number}</code> is the Firebase project that issued the Firebase App Check token (without the braces).
<li>If desired, you can also check that the <code><Subject></code> matches your app's App ID.
</li>
</ul>
<p>
Following these steps, your configuration should look like the following:
</p>
<pre class="prettyprint"><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWT continueOnError="false" enabled="true"
name="Firebase-App-Check-Token-Verification">
<DisplayName>Firebase App Check Token Verification</DisplayName>
<Algorithm>RS256</Algorithm>
<Source>request.headers.X-Firebase-AppCheck</Source>
<PublicKey>
<JWKS uri="https://firebaseappcheck.googleapis.com/v1beta/jwks"/>
</PublicKey>
<!-- Be sure to use your real project number in <Issuer> and <Audience>. -->
<Issuer>https://firebaseappcheck.googleapis.com/123456789</Issuer>
<Audience>projects/123456789</Audience>
<!-- You can also optionally check that the Subject matches your app's App Id. -->
<Subject><!-- Insert your app's App ID here. --></Subject>
</VerifyJWT>
</pre>
<p>
Finally, add this policy to your Proxy Endpoint's pre-flow, and save this configuration as a new revision. Once you re-deploy the proxy at this revision, any request that arrives at the proxy must have a valid Firebase App Check token in the <code>X-Firebase-AppCheck</code> header, or the request will be rejected.
</p>
<h2>Conclusion</h2>
<p>
Securing your app and your resources is critical. Using Firebase Authentication and Firebase Security Rules helps protect access to user data, and using Firebase App Check helps mitigate fraud and secure access to your backend resources—whether those are Firebase resources or your own. <a href="https://firebase.google.com/learn/pathways/firebase-app-check">View the full learning pathway</a> on protecting your app from abuse for additional resources.
</p>
<p>
And don’t forget to <a href="https://firebase.google.com/summit">register for Firebase Summit</a> and join us on November 10th to learn how Firebase can help you accelerate your app development, release with confidence and scale with ease!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-32337999377585333672021-10-05T09:30:00.000-07:002021-10-05T09:30:18.083-07:00Register now for Firebase Summit 2021<meta name="twitter:image" content="https://1.bp.blogspot.com/-sZAe-2uKX6A/YVtcgGffX8I/AAAAAAAAF4Y/GQjFQ7NssWQEV_95ZD2kRCLHdjbwD4UjwCLcBGAsYHQ/s0/Firebase_Summit_Medium_TwitterCrop_Header.png">
<img style="display:none" src="https://1.bp.blogspot.com/-sZAe-2uKX6A/YVtcgGffX8I/AAAAAAAAF4Y/GQjFQ7NssWQEV_95ZD2kRCLHdjbwD4UjwCLcBGAsYHQ/s0/Firebase_Summit_Medium_TwitterCrop_Header.png">
<figure class="profile">
<div class="profile-picture">
<img src="https://1.bp.blogspot.com/-odC3jlC8URQ/X0WHdESdWEI/AAAAAAAAE_4/V3m0ytTvF2oGYHqr3DgC7NKhWw2xt_t5ACLcBGAsYHQ/s1600/Akua.jpg" style="margin:0 0 0 0%; max-height:100%;" />
</div>
<figcaption>
<strong><div>
</div>
</strong>
<em>Akua Prempeh, Developer Marketing</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-ggNonTKLlCA/YVeoqJIpJXI/AAAAAAAAF38/zvXO6zNxZ48lSf2SSj7mvTHfqZgQIQbzACLcBGAsYHQ/s0/FB%2BBLOG%2Bbanner.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image from Firebase Summit promotion showing animated mountains with text that reads Firebase Summit 2021 November 10" border="0" data-original-height="152" data-original-width="512" src="https://1.bp.blogspot.com/-ggNonTKLlCA/YVeoqJIpJXI/AAAAAAAAF38/zvXO6zNxZ48lSf2SSj7mvTHfqZgQIQbzACLcBGAsYHQ/s0/FB%2BBLOG%2Bbanner.png"/></a></div>
<p>
The journey of building and releasing an app can sometimes feel like scaling a mountain – both can be filled with hurdles and require a lot of hard work. At Firebase, our goal is to make this journey easier by providing you with tools and resources you need to build and grow apps users love.
</p>
<p>
That is why every year, we bring the community together at Firebase Summit to share exciting new product updates, answer your burning questions, and provide hands-on training so you can get the most out of our platform. This year won’t be any different, and we are excited to announce that <strong><em>Firebase Summit will be returning as a virtual event on November 10th, 2021 at 9:30am PST</em></strong>. We also have a few exciting activities leading up to Firebase Summit, so read on for what to expect.
</p>
<p>
<strong>Hands-on Learning Experiences</strong>
</p>
<p>
To help you get ready for Firebase Summit, and deepen your knowledge about our products and services, we’ll release a new set of learning pathways every week leading up to the main event. These learning pathways will consist of easy-to-follow codelabs, articles, interactive videos, and quizzes. After completing a pathway, you’ll also have the opportunity to earn a shiny new Google developer badge. The first weekly pathway will launch on <em>October 13th</em>, so check out the <a href="https://firebase.google.com/summit">event website</a> for more details.
</p>
<p>
</p>
<p>
<strong>Community Talks</strong>
</p>
<p>
One of the best ways to learn about Firebase is from other developers. On November 3rd, we’ll host community talks where you will get the opportunity to hear from Google Developer Experts on topics like how to build enterprise scale apps with Firebase, implement authorization models, and so much more. Mark your calendars and visit the <a href="https://firebase.google.com/summit">event website</a> where we’ll highlight these sessions.
</p>
<p>
<strong>Live Keynote, On-demand Technical Sessions, and More</strong>
</p>
<p>
The pathways and community talks lead up to Firebase Summit on November 10th, which will kick off with a jam-packed keynote at 9:30 am PST. Join us to learn how Firebase can help you accelerate app development, run your app with confidence, and scale your business with ease. After the keynote, you can ask questions in the chat and have them answered <em>live</em> by the Firebase team during #AskFirebase. We will also have new on-demand technical sessions on our latest announcements, and demos that you can view at your convenience.
</p>
<p>
We’ll be sharing more details about Firebase Summit 2021 in the coming weeks so stay tuned. In the meantime, <a href="https://firebase.google.com/summit">register for the event</a>, subscribe to the <a href="https://www.youtube.com/user/Firebase">Firebase YouTube channel</a>, and follow us on <a href="http://twitter.com/firebase">Twitter </a>to join the conversation. #FirebaseSummit
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-65761418340393380792021-09-30T10:00:00.000-07:002021-09-30T10:00:11.968-07:00Analytics Labels for Messaging Campaigns<meta name="twitter:image" content="https://1.bp.blogspot.com/-6MO3sOwmwZI/YVNubM-OJTI/AAAAAAAAF30/zg6oxU6ssQM331MuFykD_D4rPR65V9fNgCLcBGAsYHQ/s0/Social.png">
<img style="display:none" src="https://1.bp.blogspot.com/-6MO3sOwmwZI/YVNubM-OJTI/AAAAAAAAF30/zg6oxU6ssQM331MuFykD_D4rPR65V9fNgCLcBGAsYHQ/s0/Social.png">
<figure class="profile">
<div class="profile-picture">
<img alt="Andrea Wu"
src="https://1.bp.blogspot.com/-wE3xjDZVZW4/YVNmFGsJKII/AAAAAAAAF28/IULfITMewuMK5V89pCfhvGJDiHq6xlORwCLcBGAsYHQ/s0/Andrea%2BWu.jpeg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Andrea Wu</div>
</strong>
<em>Software Engineer </em>
</figcaption>
</figure>
<p>
As an app developer, you probably send hundreds of app notifications to users nudging them to try a new game level, complete a purchase, read a new article, or so on. But have you ever wondered what impact those notifications are having on user behavior? Are they actually improving the metrics you care about?
</p>
<p>
<a href="https://firebase.google.com/products/cloud-messaging">Firebase Cloud Messaging</a> enables you to deliver and receive messages and notifications on Android, iOS, and the web at no cost. Measuring the impact of these notifications is an important but somewhat difficult task to accomplish. Cloud Messaging has always used Google Analytics to count sent notifications, and now, there’s a new way to see other user events related to an open notification across sessions or a longer period of time. Using these events will not only provide more information about the notifications you’re sending to users, they will also enable you to better measure the impact of sending notifications to users.
</p>
<p>
With analytics labels in Cloud Messaging, you have the ability to pick and apply analytics labels to messages, which Google Analytics can use to track all events related to your notifications beyond just counting sent ones. What is an <a href="https://firebase.google.com/docs/cloud-messaging/understand-delivery?authuser=0#adding-analytics-labels-to-messages">analytics label</a>? The label is a text string that you can add to any message. For example, let’s say you wanted to see all of the opened notifications for users who signed up in January. You can now do that by attaching a “january” label to your notifications when sending.
</p>
<p>
You can attach a label for any notification sent via the Firebase Cloud Messaging <a href="https://firebase.google.com/docs/reference/fcm/rest">API</a> as well as for a messaging campaign in Firebase Console. When you set up a Cloud Messaging campaign in the <a href="https://console.firebase.google.com/project/_/notification">Notifications composer</a>, you can use the dropdown menu in step 4 for Conversion events to choose an analytics label.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-RYVUM7PjH-I/YVNnVQRFPVI/AAAAAAAAF3E/CwfHwSd8aHYZwWWBdUC6BJpubPCFjeqfgCLcBGAsYHQ/s0/FB%2BBLOG%2BAnalytics%2BLabels%2B1.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="When you set up a Cloud Messaging campaign in the Notifications composer, you can use the dropdown menu in step 4 for Conversion events to choose an analytics label" border="0" data-original-height="231" data-original-width="437" src="https://1.bp.blogspot.com/-RYVUM7PjH-I/YVNnVQRFPVI/AAAAAAAAF3E/CwfHwSd8aHYZwWWBdUC6BJpubPCFjeqfgCLcBGAsYHQ/s0/FB%2BBLOG%2BAnalytics%2BLabels%2B1.png"/></a></div>
<p>
This will attach an analytics label to all messages sent as part of this campaign.
</p>
<p>
After some time has passed, you can get insight into the impact of those messages. Cloud Messaging in <a href="https://console.firebase.google.com">Firebase Console</a> has a Reports tab with a graph showing <a href="https://firebase.google.com/docs/cloud-messaging/understand-delivery#notification-funnel-analysis">funnel analysis</a> - the number of sends, received, impressions, and opened notifications for a given timeframe. Filtering using an analytics label shows the information for just that label.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-6jV9m0dkLes/YVNpwXg269I/AAAAAAAAF3U/fMw0KE3jMD42Hi15esUnqdrzw14tySEHwCLcBGAsYHQ/s0/FB%2BBLOG%2B2%2BREDO.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Filtering using an analytics label shows the information for just that label" border="0" data-original-height="396" data-original-width="728" src="https://1.bp.blogspot.com/-6jV9m0dkLes/YVNpwXg269I/AAAAAAAAF3U/fMw0KE3jMD42Hi15esUnqdrzw14tySEHwCLcBGAsYHQ/s0/FB%2BBLOG%2B2%2BREDO.png"/></a></div>
<p>
Aside from being able to see the impact of labels in Reports, you can use them to perform other specific Google Analytics analyses. For example, perhaps you want to compare how your game play time during winter holidays performed against summertime; you can use <a href="https://support.google.com/analytics/answer/9269518?hl=en">comparisons</a> to evaluate metrics like engagement time for those two different messaging campaigns. You can also use the <a href="https://support.google.com/analytics/answer/9670133">cohort exploration</a> feature to compare user activity, and in fact, you can use the labels as event parameters on the messages for any Google Analytics analyses!
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-5kRDKuIdYFo/YVNsFh8qLKI/AAAAAAAAF3s/GQPxkIqneX4gmBQjdrSKWHEf4cScTssUACLcBGAsYHQ/s0/FB%2BBLOG%2BAnalytics%2BLabels%2B3.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Viewing User Engagement card with label comparisons applied" border="0" data-original-height="223" data-original-width="512" src="https://1.bp.blogspot.com/-5kRDKuIdYFo/YVNsFh8qLKI/AAAAAAAAF3s/GQPxkIqneX4gmBQjdrSKWHEf4cScTssUACLcBGAsYHQ/s0/FB%2BBLOG%2BAnalytics%2BLabels%2B3.png"/></a></div>
<p id="imgCaption">Viewing User Engagement card with label comparisons applied.</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-aTiB3Il-75o/YVNreR1AFjI/AAAAAAAAF3k/EqdVoN61HdYo5cAkXoeiM2CQ-K8LX9MIQCLcBGAsYHQ/s0/FB%2BBLOG%2BAnalytics%2BLabels%2B4.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Cohort analysis using labeled notification campaign segments" border="0" data-original-height="427" data-original-width="512" src="https://1.bp.blogspot.com/-aTiB3Il-75o/YVNreR1AFjI/AAAAAAAAF3k/EqdVoN61HdYo5cAkXoeiM2CQ-K8LX9MIQCLcBGAsYHQ/s0/FB%2BBLOG%2BAnalytics%2BLabels%2B4.png"/></a></div>
<p id="imgCaption">Cohort analysis using labeled notification campaign segments.</p>
<p>
So there we have it! Using analytics labels in Cloud Messaging, we are able to leverage the full power of Google Analytics to measure the impact of messages sent via the API and Firebase Console!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-63905392696924122552021-09-27T10:00:00.000-07:002021-09-27T10:00:04.720-07:00Simplify the Process of Uploading iOS dSYM Files to Crashlytics with Fastlane<meta name="twitter:image" content="https://1.bp.blogspot.com/-jQDG7iNI3ns/YU0LjmYnPHI/AAAAAAAAF2k/I6xdhMqb6JwaXoU2Et-FjS8MeWiXJXVBgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BSimplify%2Bthe%2BProcess%2Bof%2BUploading%2BiOS%2BdSYM%2BFiles%2Bto%2BCrashlytics%2Bwith%2BFastlane%2B.png">
<img style="display:none" src="https://1.bp.blogspot.com/-jQDG7iNI3ns/YU0LjmYnPHI/AAAAAAAAF2k/I6xdhMqb6JwaXoU2Et-FjS8MeWiXJXVBgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BSimplify%2Bthe%2BProcess%2Bof%2BUploading%2BiOS%2BdSYM%2BFiles%2Bto%2BCrashlytics%2Bwith%2BFastlane%2B.png">
<figure class="profile">
<div class="profile-picture">
<img alt="Elena Doty"
src="https://1.bp.blogspot.com/-VdPZ3i5I3vM/YU0KzHn6PvI/AAAAAAAAF2c/Z050qo3hnBUO6bRaS8fS8aXOvzmgVX8ZQCLcBGAsYHQ/s0/Elena%2BDoty.jpeg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Elena Doty</div>
</strong>
<em>Software Engineer </em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-jQDG7iNI3ns/YU0LjmYnPHI/AAAAAAAAF2k/I6xdhMqb6JwaXoU2Et-FjS8MeWiXJXVBgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BSimplify%2Bthe%2BProcess%2Bof%2BUploading%2BiOS%2BdSYM%2BFiles%2Bto%2BCrashlytics%2Bwith%2BFastlane%2B.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Header image from Firebase blog titled Simplify the process of uploading iOS dSYM files to Crashlytics by using fastlane" border="0" data-original-height="269" data-original-width="512" src="https://1.bp.blogspot.com/-jQDG7iNI3ns/YU0LjmYnPHI/AAAAAAAAF2k/I6xdhMqb6JwaXoU2Et-FjS8MeWiXJXVBgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BSimplify%2Bthe%2BProcess%2Bof%2BUploading%2BiOS%2BdSYM%2BFiles%2Bto%2BCrashlytics%2Bwith%2BFastlane%2B.png"/></a></div>
<p>
We’ve heard your feedback about the challenges you’ve experienced when uploading dSYMs to Crashlytics, especially for apps with bitcode enabled. We’re working to improve this process and wanted to share a way to automate it by using fastlane.
</p>
<h4><strong>The current process</strong></h4>
<p>
When building apps <em>without</em> bitcode, the Crashlytics <code>upload-symbols</code> tool that you include as a run script automatically uploads your app’s dSYM files every time you rebuild your app. When the app sends us crash reports, these files allow us to symbolicate the stack frames included in the reports so that you see source code rather than compiled code on the Crashlytics dashboard.
</p>
<p>
However, for apps with bitcode enabled, the process of uploading dSYMs isn’t automatic. Instead, you need to download updated dSYMs from Apple and upload them manually to Crashlytics each time you submit a new version of the app to App Store Connect.
</p>
<p>
This manual process can be a pain especially since non-technical team members are often responsible for uploading bitcode dSYMs.With fastlane, you can use a single command to automatically download and upload your bitcode dSYMs.
</p>
<h4><strong>What is fastlane?</strong></h4>
<p>
Fastlane is an open-source tool that automates the build and release workflow for iOS and Android apps, including tasks like code signing and generating screenshots. See the <a href="https://docs.fastlane.tools/">official fastlane documentation</a> for more information.
</p>
<p>
There are a couple of fastlane tools that will help you automate the process of uploading dSYMs to Crashlytics: <code>actions</code>, <code>lanes</code>, and <code>Fastfiles</code>.
</p>
<p>
An <code>action</code> is one of the building blocks of fastlane. Each <code>action</code> performs a single command, such as running tests or performing code validation.
</p>
<p>
One or more <code>actions</code> can be included in a <code>lane</code>. You can think of a <code>lane</code> as a workflow that is (usually) composed of related tasks. For this Crashlytics workflow, the <code>lane</code> will consist of three actions: downloading dSYMs from Apple, uploading dSYMs to Crashlytics, then cleaning up the files. Each <code>lane</code> also has a name and description.
</p>
<p>
And finally, a <code>Fastfile</code> manages the <code>lane</code> created in this workflow, as well as any others you use for your project.
</p>
<h3><strong>Configure fastlane with Crashlytics</strong></h3>
<p>
You can set up fastlane in multiple ways, including with Bundler and Homebrew. For instructions, see fastlane's <a href="https://docs.fastlane.tools/getting-started/ios/setup/">Getting Started for iOS guide. </a>During the <code>fastlane init</code> step, make sure to choose the <em>manual setup</em> option.
</p>
<p>
Once fastlane is set up, the first step toward automating symbol uploads is configuring a lane. We’ll do this by editing the <code>Fastfile</code> that was created in the <code>fastlane</code> directory during the setup step. Let's start by modifying the default lane, which currently looks like this:
</p>
<pre class="prettyprint">desc "Description of what the lane does"
lane :custom_lane do
# add actions here: https://docs.fastlane.tools/actions
end
</pre>
<p>
For the <code>desc</code> field, we’ll include a brief summary of the lane’s purpose:
</p>
<pre class="prettyprint">desc "Downloads dSYM files from Apple for a given app version and uploads them to Crashlytics"
</pre>
<p>
And then give the lane a name:
</p>
<pre class="prettyprint">lane :upload_symbols do
</pre>
<p>
Next, we'll add actions to our lane. There are three actions that we'll use: <code><a href="https://www.google.com/url?q=https://docs.fastlane.tools/actions/download_dsyms/&sa=D&source=editors&ust=1625672358972000&usg=AOvVaw2APLqF7NK-UTVTwXCxPntb">download_dsyms</a></code>, <code><a href="https://www.google.com/url?q=https://docs.fastlane.tools/actions/upload_symbols_to_crashlytics/&sa=D&source=editors&ust=1625672358972000&usg=AOvVaw0Bi5BGaFvYkYQzb2F8m77I">upload_symbols_to_crashlytics</a></code>, and <code><a href="http://docs.fastlane.tools/actions/clean_build_artifacts/#clean_build_artifacts">clean_build_artifacts</a></code>. (For fastlane’s documentation on any of these commands, run <code>fastlane action command_name</code> in your terminal.)
<p>
<code>download_dsyms</code> will do the work of downloading the new dSYM files from Apple. We’ll just need to provide the action with either 1) the version number and build for the app version that you want to download dSYMs for or 2) the <code>live</code> and <code>latest</code> version constants to download the live or latest version’s dSYMs, respectively. Optionally, you can also specify your app’s bundle ID and your App Store Connect username to avoid having to enter them manually when you run the action. All in all, this action will look similar to one of the following:
</p>
<ul>
<li>Specific version and build, specifying bundle ID, but no App Store Connect username:<code> download_dsyms(version: "1.0.0", build: "1.0.0", app_identifier: "bundleID")</code>
<li>Live version, no App Store Connect username or app bundle ID: <code>download_dsyms(version: "live")</code>
<li>Latest version, specifying bundle ID and App Store Connect username:<code> download_dsyms(username: "username", version: "latest", app_identifier: "bundleID")</code>
</ul>
<p>
In this guide, we'll use the last option (i.e, latest version, specifying both bundle ID and App Store Connect username).
</p>
<p><code>upload_symbols_to_crashlytics</code> will take the files from <code>download_dsyms</code> and upload them to Crashlytics. This command takes as a parameter the <code>GoogleService-Info.plist</code> file for the app, like so:<br>
<code>upload_symbols_to_crashlytics(gsp_path: "path/to/GoogleService-Info.plist")</code>
</p>
<p>
<strong>Note:</strong> If you’re using Swift Package Manager (instead of CocoaPods), you’ll need to <a href="https://github.com/firebase/firebase-ios-sdk/raw/master/Crashlytics/upload-symbols">download</a> the Crashlytics upload-symbols tool, place it in your project directory, make it executable (<code>chmod +x upload-symbols</code>), then set the <code>binary_path</code> variable in the <code>upload_symbols_to_crashlytics</code> action: <code>upload_symbols_to_crashlytics(gsp_path: "path/to/GoogleService-Info.plist", binary_path: "upload-symbols")</code>.
</p>
<p>
<br>Lastly, we’ll use <code>clean_build_artifacts</code> to delete the dSYM files once they’ve been uploaded.
</p>
<p>
Our lane now looks something like this:
</p>
<pre class="prettyprint">desc "Downloads dSYM files from Apple for a given app build and version and uploads them to Crashlytics"
lane :upload_symbols do
download_dsyms(username: "username", version: "latest", app_identifier: "bundleID")
upload_symbols_to_crashlytics(gsp_path: "path/to/GoogleService-Info.plist")
clean_build_artifacts
end
</pre>
<p>
(If you’re using Swift Package Manager, the only difference will be the <code>binary_path</code> variable in the <code>upload_symbols_to_crashlytics</code> action.)
</p>
<p>
And here's our Fastfile with just this one lane:
</p>
<pre class="prettyprint">default_platform(:ios)
platform :ios do
desc "Downloads dSYM files from Apple for a given app version and uploads them to Crashlytics"
lane :upload_symbols do
download_dsyms(username: "username", version: "latest", app_identifier: "bundleID")
upload_symbols_to_crashlytics(gsp_path: "path/to/GoogleService-Info.plist")
clean_build_artifacts
end
end
</pre>
<p>
To run this lane, run <code>fastlane upload_symbols</code> from the terminal inside your project folder (replace <code>upload_symbols</code> if you chose a different name for the lane). You’ll be asked to log into your App Store Connect account (and select your App Store Connect team, if you have more than one associated with your account). If needed, you can customize the actions in the file to include more information about your account to avoid having to log in manually.
</p>
<h3><strong>What’s next?</strong></h3>
<p>
<a href="https://docs.fastlane.tools/getting-started/ios/setup/">Get started with fastlane</a> and start automating your dSYM uploads!
</p>
<p>
We’re always looking for ways to make Crashlytics work better for developers. We want to thank everyone who has provided us with feedback on <a href="https://github.com/firebase/firebase-ios-sdk">GitHub</a>, Firebase Support, and other channels about the dSYM upload process, and we encourage you to continue to reach out with questions and suggestions!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-76253637501597293432021-09-24T10:01:00.000-07:002021-09-24T10:01:58.084-07:00Converting between Firestore FieldValue and Variant<meta name="twitter:image" content="https://1.bp.blogspot.com/-DDPTCCmSqPU/YUyrXu9Y6bI/AAAAAAAAF2M/mfvkd6jl6PUhjosfpNCKe1MP6gmUailOgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BConverting%2Bbetween%2BFirestore%2BFieldValue%2Band%2BVariant%2Bin%2BC%252B%252B%2B.png">
<img style="display:none" src="https://1.bp.blogspot.com/-DDPTCCmSqPU/YUyrXu9Y6bI/AAAAAAAAF2M/mfvkd6jl6PUhjosfpNCKe1MP6gmUailOgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BConverting%2Bbetween%2BFirestore%2BFieldValue%2Band%2BVariant%2Bin%2BC%252B%252B%2B.png">
<figure class="profile">
<div class="profile-picture">
<img alt="Konstantin Varlamov"
src="https://1.bp.blogspot.com/-G5mRa-epqKg/YUy8VCimI_I/AAAAAAAAF2U/JvBr4JyclnMHrG0NaXf8XXTt9UuVLtgbwCLcBGAsYHQ/s0/1621471012288.jpeg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Konstantin Varlamov</div>
</strong>
<em>Senior Software Engineer </em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-DDPTCCmSqPU/YUyrXu9Y6bI/AAAAAAAAF2M/mfvkd6jl6PUhjosfpNCKe1MP6gmUailOgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BConverting%2Bbetween%2BFirestore%2BFieldValue%2Band%2BVariant%2Bin%2BC%252B%252B%2B.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Header image from Firebase blog titled Converting between Firestore FieldValue and Variant in C++" border="0" data-original-height="152" data-original-width="512" src="https://1.bp.blogspot.com/-DDPTCCmSqPU/YUyrXu9Y6bI/AAAAAAAAF2M/mfvkd6jl6PUhjosfpNCKe1MP6gmUailOgCLcBGAsYHQ/s0/%255BFB%2BBLOG%255D%2BConverting%2Bbetween%2BFirestore%2BFieldValue%2Band%2BVariant%2Bin%2BC%252B%252B%2B.png"/></a></div>
<h2>Introduction</h2>
<p>
The Cloud Firestore C++ SDK uses the <code>firebase::firestore::FieldValue</code> class to represent document fields. A <code>FieldValue</code> is a union type that may contain a primitive (like a boolean or a double), a container (e.g. an array), some simple structures (such as a <code>Timestamp</code>) or some Firestore-specific sentinel values (e.g. <code>ServerTimestamp</code>) and is used to write data to and read data from a Firestore database.
</p>
<p>
Other Firebase C++ SDKs use <code>firebase::Variant</code> for similar purposes. A <code>Variant</code> is also a union type that may contain primitives or containers of nested <code>Variant</code>s; it is used, for example, to write data to and read data from the Realtime Database, to represent values read from Remote Config, and to represent the results of calling Cloud Functions using the Firebase SDK. If your application is migrating from Realtime Database to Firestore (or uses both side-by-side), or, for example, uses Firestore to store the results of Cloud Functions, you might need to convert between <code>Variant</code>s and <code>FieldValue</code>s.
</p>
<p>
In many ways, <code>FieldValue</code> and <code>Variant</code> are similar. However, it is important to understand that for all their similarities, neither is a subset of the other; rather, they can be seen as overlapping sets, each reflecting its domain. These differences make it impossible to write a general-purpose converter between them that would cover each and every case -- instead, handling each instance where one type doesn’t readily map to the other would by necessity have to be application-specific.
</p>
<p>
With that in mind, let’s go through some sample code that provides one approach to conversion; if your application needs to convert between <code>FieldValue</code> and <code>Variant</code>, it should be possible to adapt this code to your needs. Full sample code is available <a href="https://github.com/firebase/snippets-cpp/tree/b5ef01ab756bd39571b1d79736684f768bf27af6/blogs/sept-2021">here</a>.
</p>
<h2>Converting primitives</h2>
<p>
The one area where <code>FieldValue</code>s and <code>Variant</code>s correspond to each other exactly are the primitive values. Both <code>FieldValue</code> and <code>Variant</code> support the exact same set of primitives, and conversion between them is straightforward:
</p>
<pre class="prettyprint">FieldValue ConvertVariantToFieldValue(const Variant& from) {
switch (from.type()) {
case Variant::Type::kTypeNull:
return FieldValue::Null();
case Variant::Type::kTypeBool:
return FieldValue::Boolean(from.bool_value());
case Variant::Type::kTypeInt64:
return FieldValue::Integer(from.int64_value());
case Variant::Type::kTypeDouble:
return FieldValue::Double(from.double_value());
}
}
Variant Convert(const FieldValue& from) {
switch (from.type()) {
case FieldValue::Type::kNull:
return Variant::Null();
case FieldValue::Type::kBoolean:
return Variant(from.boolean_value());
case FieldValue::Type::kInteger:
return Variant(from.integer_value());
case FieldValue::Type::kDouble:
return Variant(from.double_value());
}
}
</pre>
<h2>Strings and blobs</h2>
<p>
<code>Variant</code> distinguishes between <em>mutable</em> and <em>static</em> strings and blobs: a mutable string (or blob) is owned by the <code>Variant</code> and can be modified through its interface, whereas a static string (or blob) is <em>not</em> owned by the <code>Variant</code> (so the application needs to ensure it stays valid as long as the <code>Variant</code>’s lifetime hasn’t ended; typically, this is only used for static strings) and cannot be modified.
</p>
<p>
Firestore does not have this distinction -- the strings and blobs held by <code>FieldValue</code> are always immutable (like static strings or blobs in <code>Variant</code>) but owned by the <code>FieldValue</code> (like mutable strings or blobs in <code>Variant</code>). Because ownership is the more important concern here, Firestore strings and blobs should be converted to mutable strings and blobs in <code>Variant</code>:
</p>
<pre class="prettyprint"> // `FieldValue` -> `Variant`
case FieldValue::Type::kString:
return Variant(from.string_value());
case FieldValue::Type::kBlob:
return Variant::FromMutableBlob(from.blob_value(), from.blob_size());
// `Variant` -> `FieldValue`
case Variant::Type::kTypeStaticString:
case Variant::Type::kTypeMutableString:
return FieldValue::String(from.string_value());
case Variant::Type::kTypeStaticBlob:
case Variant::Type::kTypeMutableBlob:
return FieldValue::Blob(from.blob_data(), from.blob_size());
</pre>
<h2>Arrays and maps</h2>
<p>
Both <code>FieldValue</code>s and <code>Variant</code>s support arrays (called “vectors” by <code>Variant</code>) and maps, so for the most part, converting between them is straightforward:
</p>
<pre class="prettyprint"> // `FieldValue` -> `Variant`
case FieldValue::Type::kArray:
return ConvertArray(from.array_value());
case FieldValue::Type::kMap:
return ConvertMap(from.map_value());
}
// `Variant` -> `FieldValue`
case Variant::Type::kTypeVector:
return ConvertArray(from.vector());
case Variant::Type::kTypeMap:
return ConvertMap(from.map());
}
// ...
FieldValue ConvertArray(const std::vector<Variant>& from) {
std::vector<FieldValue> result;
result.reserve(from.size());
for (const auto& v : from) {
result.push_back(Convert(v));
}
return FieldValue::Array(std::move(result));
}
FieldValue ConvertMap(const std::map<Variant, Variant>& from) {
MapFieldValue result;
for (const auto& kv : from) {
// Note: Firestore only supports string keys. If it's possible
// for the map to contain non-string keys, you would have to
// convert them to a string representation or skip them.
assert(kv.first.is_string());
result[kv.first.string_value()] = Convert(kv.second);
}
return FieldValue::Map(std::move(result));
}
Variant ConvertArray(const std::vector<FieldValue>& from) {
std::vector<Variant> result;
result.reserve(from.size());
for (const auto& v : from) {
result.push_back(Convert(v));
}
return Variant(result);
}
Variant ConvertMap(const MapFieldValue& from) {
std::map<Variant, Variant> result;
for (const auto& kv : from) {
result[Variant(kv.first)] = Convert(kv.second);
}
return Variant(result);
}
</pre>
<h3>Nested arrays</h3>
<p>
Firestore does not support nested arrays (that is, one array being a direct member of another array). <code>FieldValue</code> itself would not reject a nested array, though -- it will only be rejected by Firestore’s input validation when passed to a Firestore instance (like in a call to <code>DocumentReference::Set</code>).
</p>
<p>
The approach to handling this case would have to be application-specific. For example, you might simply omit nested arrays, perhaps logging a warning upon encountering them; on the other extreme, you may want to terminate the application:
</p>
<pre class="prettyprint">FieldValue ConvertArray(const std::vector<Variant>& from) {
std::vector<FieldValue> result;
result.reserve(from.size());
for (const auto& v : from) {
if (v.type() == Variant::Type::kTypeVector) {
// Potential approach 1: log and forget
LogWarning("Skipping nested array");
continue;
// Potential approach 2: terminate
assert(false && "Encountered a nested array");
std::terminate();
}
result.push_back(Convert(v));
}
return FieldValue::Array(std::move(result));
}
</pre>
<p>
Yet another approach might be to leave the nested arrays in place and rely on Firestore input validation to reject them (this approach is mostly applicable if you don’t expect your data to contain any nested arrays).
</p>
<h3>Translating nested arrays</h3>
<p>
One possible workaround if you need to pass a nested array to Firestore might be to represent arrays as maps:
</p>
<pre class="prettyprint"> case Variant::Type::kTypeVector: {
MapFieldValue result;
const std::vector<Variant>& array = from.vector();
for (int i = 0; i != array.size(); ++i) {
result[std::to_string(i)] = Convert(array[i]);
}
return FieldValue::Map(std::move(result));
}
</pre>
<p>
Another approach, which has the nice property of being generalizable to other cases, is to automatically translate the structure of “array-array” into “array-map-array” when converting to <code>FieldValue</code>.
</p>
<p>
If you decide to use this approach, you will need to ensure that the translated structure roundtrips properly (assuming your application needs bidirectional conversion). That is, an “array-map-array” structure within a <code>FieldValue</code> converts back to an “array-array” structure in <code>Variant</code>. To achieve this, the artificial map would have to be somehow marked to indicate that it does not represent an actual value in the database.
</p>
<p>
Once again, the implementation for this would be application-specific. You could add a boolean field called “special” with its value set to <code>true</code> and establish a convention that a map that contains a “special” field never represents user input. If this is not true for your application, you might use a more distinct name than “special” or come up with a different convention altogether.
</p>
<p>
These next two examples use “special” as a marker, but please keep in mind that it’s just one possible approach:
</p>
<pre class="prettyprint">// `Variant` -> `FieldValue`
FieldValue Convert(const Variant& from, bool within_array = false) {
switch (from.type()) {
// ...
case Variant::Type::kTypeVector:
if (!within_array) {
return ConvertArray(from.vector());
} else {
// Firestore doesn't support nested arrays. As a workaround, create an
// intermediate map to contain the nested array.
return FieldValue::Map({
{"special", FieldValue::Boolean(true)},
{"type", FieldValue::String("nested_array")},
{"value", ConvertArray(from.vector())},
});
}
}
}
FieldValue ConvertArray(const std::vector<Variant>& from) {
std::vector<FieldValue> result;
result.reserve(from.size());
for (const auto& v : from) {
result.push_back(Convert(v, /*within_array=*/true));
}
return FieldValue::Array(std::move(result));
}
// `FieldValue` -> `Variant`
Variant Convert(const FieldValue& from) {
switch (from.type()) {
// ...
case FieldValue::Type::kArray:
return ConvertArray(from.array_value());
case FieldValue::Type::kMap: {
const auto& m = from.map_value();
// Firestore doesn't support nested arrays, so nested arrays are instead
// encoded as an "array-map-array" structure. Make sure nested arrays
// round-trip.
// Note: `TryGet*` functions are helpers to simplify getting values
// out of maps. See their definitions in the full sample code.
bool is_special = TryGetBoolean(m, "special");
if (is_special) {
return ConvertSpecialValue(m);
} else {
return ConvertMap(from.map_value());
}
}
}
Variant ConvertSpecialValue(const MapFieldValue& from) {
// Note: in production code, you would have to handle
// the case where the value is not in the map.
// Note: `TryGet*` functions are helpers to simplify getting values
// out of maps. See their definitions in the full sample code.
std::string type = TryGetString(from, "type");
if (type == "nested_array") {
// Unnest the array.
return ConvertArray(TryGetArray(from, "value"));
}
// ...
}
</pre>
<h2>Firestore structs</h2>
<p>
Finally, there are several kinds of entities supported by <code>FieldValue</code> that have no direct equivalent in <code>Variant</code>:
</p>
<ul>
<li><code>Timestamp</code>
<li><code>GeoPoint</code>
<li><code>DocumentReference</code>
<li>Sentinel values (see below).
</ul>
<p>
Similarly to nested arrays, your application could omit these values, issue errors upon encountering them, or else convert them into some representation supported by <code>Variant</code>. The exact representation would depend on the needs of your application and on whether the conversion is bidirectional or not (that is, whether it should be possible to convert the representation back into the original Firestore type).
</p>
<p>
An approach that is general (if somewhat heavyweight) and allows bidirectional conversion is to convert such structs into “special” maps. It could look like this:
</p>
<pre class="prettyprint"> // `FieldValue` -> `Variant`
case FieldValue::Type::kTimestamp: {
Timestamp ts = from.timestamp_value();
MapFieldValue as_map = {
{"special", FieldValue::Boolean(true)},
{"type", FieldValue::String("timestamp")},
{"seconds", FieldValue::Integer(ts.seconds())},
{"nanoseconds", FieldValue::Integer(ts.nanoseconds())}};
return ConvertMap(as_map);
}
case FieldValue::Type::kGeoPoint: {
GeoPoint gp = from.geo_point_value();
MapFieldValue as_map = {
{"special", FieldValue::Boolean(true)},
{"type", FieldValue::String("geo_point")},
{"latitude", FieldValue::Double(gp.latitude())},
{"longitude", FieldValue::Double(gp.longitude())}};
return ConvertMap(as_map);
}
case FieldValue::Type::kReference: {
DocumentReference ref = from.reference_value();
std::string path = ref.path();
MapFieldValue as_map = {
{"special", FieldValue::Boolean(true)},
{"type", FieldValue::String("document_reference")},
{"document_path", FieldValue::String(path)}};
return ConvertMap(as_map);
}
FieldValue ConvertSpecialValue(const std::map<Variant, Variant>& from) {
// Special values are Firestore entities encoded as maps because they are not
// directly supported by `Variant`. The assumption is that the map contains
// a boolean field "special" set to true and a string field "type" indicating
// which kind of an entity it contains.
std::string type = TryGetString(from, "type");
if (type == "timestamp") {
Timestamp result(TryGetInteger(from, "seconds"),
TryGetInteger(from, "nanoseconds"));
return FieldValue::Timestamp(result);
} else if (type == "geo_point") {
GeoPoint result(TryGetDouble(from, "latitude"),
TryGetDouble(from, "longitude"));
return FieldValue::GeoPoint(result);
}
// ...
</pre>
<p>
The only complication here is that to convert a “special” map back to a <code>DocumentReference</code>, you would need a pointer to a Firestore instance so that you may call <code>Firestore::Document</code>. If your application always uses the default Firestore instance, you might simply call <code>Firestore::GetInstance</code>. Otherwise, you can pass <code>Firestore*</code> as an argument to <code>Convert</code> or make <code>Convert</code> a member function of a class, say, <code>Converter</code>, that acquires a pointer to a Firestore instance in its constructor.
</p>
<pre class="prettyprint"> } else if (type == "document_reference") {
DocumentReference result =
firestore->Document(TryGetString(from, "document_path"));
return FieldValue::Reference(result);
}
</pre>
<p>
One more thing to note is that Realtime Database represents timestamps as the number of milliseconds since the epoch in UTC. If you intend to use the resulting <code>Variant</code> in the Realtime Database, a more natural representation for a <code>Timestamp</code> might thus be an integer field. However, you would have to provide some way to distinguish between numbers and timestamps in the Realtime Database -- a possible solution is to simply add a <code>_timestamp</code> suffix to the field name, but of course other alternatives are possible. In that case, the conversion from <code>FieldValue</code> to <code>Variant</code> might look like:
</p>
<pre class="prettyprint"> case FieldValue::Type::kTimestamp: {
Timestamp ts = from.timestamp_value();
int64_t millis = ts.seconds() * 1000 + ts.nanoseconds() / (1000 * 1000);
return Variant(millis);
}
</pre>
<p>
If bidirectional conversion is required, you would also have to somehow distinguish between numbers and timestamps when converting back to a <code>FieldValue</code>. If you're using the solution of adding <code>_timestamp</code> suffix to the field name, you would have to pass the field name to the converter. Another approach might be to use heuristics and presume that a very large number that readily converts to a reasonably recent date must be a timestamp.
</p>
<h2>Firestore sentinel values</h2>
<p>
Finally, there are some unique values in <code>Firestore</code> that represent a transformation to be applied to an existing value or a placeholder for a value to be supplied by the backend:
</p>
<ul>
<li><code>Delete</code>
<li><code>ServerTimestamp</code>
<li><code>ArrayUnion</code>
<li><code>ArrayRemove</code>
<li><code>IncrementInteger</code>
<li><code>IncrementDouble</code>
</ul>
<p>
Some of these values are only meaningful in Firestore, so most likely it wouldn’t make sense to try to convert them in your application. Otherwise, <code>Delete</code> and <code>ServerTimestamp</code>, being stateless, can be straightforwardly converted to maps using the approach outlined above. If you’re using <code>Variant</code> with the Realtime Database, you might want to represent a <code>ServerTimestamp</code> in the Realtime Database-specific format ( a map that contains a single element: <code>{".sv" : "timestamp"}</code>):
</p>
<pre class="prettyprint"> case FieldValue::Type::kServerTimestamp:
return ConvertMap({{".sv", FieldValue::String("timestamp")}});
</pre>
<p>
Similarly, you may represent <code>Delete</code> as a null in the Realtime Database:
</p>
<pre class="prettyprint"> case FieldValue::Type::kDelete:
return Variant::Null();
</pre>
<p>
However, other than <code>Delete</code> and <code>ServerTimestamp</code>, the rest of the sentinel values are stateful and there is no way to get their underlying value from a <code>FieldValue</code>, so lossless conversion is not possible. Likely the best thing to do is just to ensure these values are never passed to the converter and assert if they do.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-34667965287951681402021-09-10T10:00:00.001-07:002021-09-10T10:00:00.176-07:00Improvements to Crashlytics for Game Developers<meta name="twitter:image" content="https://1.bp.blogspot.com/-nazma7UD7ng/YTuHhuAU17I/AAAAAAAAF1g/uxhJD5SaJXc0yEN5r9fVrq8J_A1JFdlNgCLcBGAsYHQ/s0/dashboard.jpeg">
<img style="display:none" src="https://1.bp.blogspot.com/-nazma7UD7ng/YTuHhuAU17I/AAAAAAAAF1g/uxhJD5SaJXc0yEN5r9fVrq8J_A1JFdlNgCLcBGAsYHQ/s0/dashboard.jpeg">
<figure class="profile">
<div class="profile-picture">
<img alt="Konstantin Mandrika"
src="https://1.bp.blogspot.com/-IX0HpJf_hZw/YTuGx3CXKdI/AAAAAAAAF1Y/aHP9frvMkx8jcZZEMUXxM9vtWb-SB5wWQCLcBGAsYHQ/s0/kmandrika.jpg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Konstantin Mandrika</div>
</strong>
<em>Software Engineer </em>
</figcaption>
</figure>
<p>
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.
</p>
<h3>Improved NDK Reliability</h3>
<p>
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 <a href="https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md">Crashpad</a> 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.
</p>
<p>
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.
</p>
<h3>Higher Quality NDK Stack Traces</h3>
<p>
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 <a href="https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md">Breakpad symbol file</a>. 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.
</p>
<p>
The key to more accurate stack traces lies within the <a href="https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md#records-6">Call Frame Information</a> 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!
</p>
<p>
Take a look at the Google Games Developer Summit <a href="https://youtu.be/eb8Z3RqvDfU?t=1s">session</a> 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 <code>symbolGenerator { breakpad() }</code> to your build.gradle. Check out our <a href="https://firebase.google.com/docs/crashlytics/ndk-reports#breakpad-symbol-file">docs</a> for more info.
</p>
<a href="https://1.bp.blogspot.com/-05sTY85NP0I/YTp6mHTaBcI/AAAAAAAAF1A/GAG2HGKUlsMx8VqCFFL4YS8EMLcDtIMpgCLcBGAsYHQ/s0/side-by-side%2Bfinal.jpg" imageanchor="1" ><img id=imgFull alt="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." border="0" src="https://1.bp.blogspot.com/-05sTY85NP0I/YTp6mHTaBcI/AAAAAAAAF1A/GAG2HGKUlsMx8VqCFFL4YS8EMLcDtIMpgCLcBGAsYHQ/s0/side-by-side%2Bfinal.jpg" data-original-width="1058" data-original-height="714" /></a>
<p id="imgCaption">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.</p>
<a href="https://1.bp.blogspot.com/-9X7oU_JIvb8/YTp36tKJP0I/AAAAAAAAF0s/g6BgqODX7kYWQJ__ZoHipGVsvthcYkUGACLcBGAsYHQ/s0/top-bottom.jpg" imageanchor="1" ><img id=imgFull alt="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." border="0" src="https://1.bp.blogspot.com/-9X7oU_JIvb8/YTp36tKJP0I/AAAAAAAAF0s/g6BgqODX7kYWQJ__ZoHipGVsvthcYkUGACLcBGAsYHQ/s0/top-bottom.jpg" data-original-width="1058" data-original-height="714" /></a>
<p id="imgCaption">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.</p>
<h3>Easier NDK Integration</h3>
<p>
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.<strong> </strong> 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.
</p>
<h3>Revised Unity Grouping</h3>
<p>
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.
</p>
<a href="https://1.bp.blogspot.com/-1Rv-c2C1Kbc/YTpiFpZ5-RI/AAAAAAAAF0Y/N0ZgFus1YiI_5DRNZe6fqT1VWe5E3dz2QCLcBGAsYHQ/s0/dashboard.png" imageanchor="1" ><img id=imgFull alt="Revised Unity Grouping in Crashlytics Console" border="0" src="https://1.bp.blogspot.com/-1Rv-c2C1Kbc/YTpiFpZ5-RI/AAAAAAAAF0Y/N0ZgFus1YiI_5DRNZe6fqT1VWe5E3dz2QCLcBGAsYHQ/s0/dashboard.png" data-original-width="1058" data-original-height="714" /></a>
<p id="imgCaption">Revised Unity Grouping in Crashlytics Console</p>
<h3>Unity Game Metadata</h3>
<p>
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.
</p>
<a href="https://1.bp.blogspot.com/-SocaxmKSd2Y/YTpifRstYxI/AAAAAAAAF0g/r83bseDZPAE3m6tiaY-4SgUIuG8rvS1dQCLcBGAsYHQ/s0/final%2Bimage.png" imageanchor="1" ><img id=imgFull alt="Unity metadata in Crashlytics console" border="0" src="https://1.bp.blogspot.com/-SocaxmKSd2Y/YTpifRstYxI/AAAAAAAAF0g/r83bseDZPAE3m6tiaY-4SgUIuG8rvS1dQCLcBGAsYHQ/s0/final%2Bimage.png" data-original-width="1058" data-original-height="714" /></a>
<p id="imgCaption">Unity metadata in Crashlytics console</p>
<h2>We’re not done just yet! </h2>
<p>
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!
</p>
<p>
In the meantime to get started, head to our <a href="https://firebase.google.com/docs/crashlytics/ndk-reports">NDK</a> and <a href="https://firebase.google.com/docs/crashlytics/get-started?platform=unity">Unity</a> onboarding pages. We're excited to help you through your game development journey and can’t wait to hear what you think!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-56811047091757786702021-08-27T10:00:00.001-07:002021-08-27T10:00:00.167-07:00Firebase SDK for Apple now fully supports Swift Package Manager<meta name="twitter:image" content="https://1.bp.blogspot.com/-KMH6f_7K6GA/YSkJiZ-3i0I/AAAAAAAAFyk/jGxF_TkswXk3va1lpNmO-36XzkeVsevQACLcBGAsYHQ/s0/Firebase--Firebase-SDK-for-Apple-supports-Swift-Package-Manager-social.png">
<img style="display:none" src="https://1.bp.blogspot.com/-KMH6f_7K6GA/YSkJiZ-3i0I/AAAAAAAAFyk/jGxF_TkswXk3va1lpNmO-36XzkeVsevQACLcBGAsYHQ/s0/Firebase--Firebase-SDK-for-Apple-supports-Swift-Package-Manager-social.png">
<figure class="profile">
<div class="profile-picture">
<img alt="Peter Friese"
src="https://1.bp.blogspot.com/-tWZr1igHXnU/X5icg0oh1TI/AAAAAAAAFRY/C4Gt4RREIIk5duHugCs5W13ut--zL7PzwCLcBGAsYHQ/s0/Peter%2BFriese.jpg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
<a href="https://twitter.com/peterfriese">Peter Friese</a> </div>
</strong>
<em>Developer Advocate </em>
</figcaption>
</figure>
<figure class="profile">
<div class="profile-picture">
<img alt="Paul Beusterien"
src="https://1.bp.blogspot.com/-uwokA-A5wT0/YSbT4P_QoVI/AAAAAAAAFyY/1yYwWJVgMHIJzp8kz5WrJMS1WfWdTpaFACLcBGAsYHQ/s0/paul%2Bb.jpg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
<a href="https://twitter.com/paulbeusterien">Paul Beusterien</a> </div>
</strong>
<em>Software Engineer</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-KMH6f_7K6GA/YSkJiZ-3i0I/AAAAAAAAFyk/jGxF_TkswXk3va1lpNmO-36XzkeVsevQACLcBGAsYHQ/s0/Firebase--Firebase-SDK-for-Apple-supports-Swift-Package-Manager-social.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Firebase header" border="0" data-original-height="1027" data-original-width="2048" src="https://1.bp.blogspot.com/-KMH6f_7K6GA/YSkJiZ-3i0I/AAAAAAAAFyk/jGxF_TkswXk3va1lpNmO-36XzkeVsevQACLcBGAsYHQ/s0/Firebase--Firebase-SDK-for-Apple-supports-Swift-Package-Manager-social.png"/></a></div>
<p>
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 <code>Podfile</code> file and running <code>pod install</code>.
</p>
<p>
In recent years, Swift Package Manager has grown in popularity thanks to being officially supported by Apple, and its tight integration with Xcode. The <a href="https://iosdevsurvey.com/2020/09-dependency-management/">2020 iOS Developer Community Survey</a> 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.
</p>
<p>
Adding support for Swift Package Manager has been <a href="https://github.com/firebase/firebase-ios-sdk/issues/3136">one of the most requested features</a> in our issue tracker:
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-pJyQDyXLkNw/YSbRrKgE49I/AAAAAAAAFyM/kPfIe_ZQt8UmiuiZoGB4m2z6gIWvaiYRgCLcBGAsYHQ/s0/unnamed%2B%25286%2529.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="image showing a comment from a user asking for iOS support" border="0" data-original-height="105" data-original-width="512" src="https://1.bp.blogspot.com/-pJyQDyXLkNw/YSbRrKgE49I/AAAAAAAAFyM/kPfIe_ZQt8UmiuiZoGB4m2z6gIWvaiYRgCLcBGAsYHQ/s0/unnamed%2B%25286%2529.png"/></a></div>
<p>
Firebase shipped initial (beta) support for Swift Package Manager in August 2020 with Firebase 6.31.0 for a partial set of Firebase products. </p>
<p>Today, we are excited to announce that as of <a href="https://firebase.google.com/support/release-notes/ios#sdk_version_330_-_june_29_2016">Firebase 8.6.0 for iOS</a>, 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.
</p>
<h3>How to add Firebase using SwiftPM</h3>
<p>
Adding Firebase to your iOS project is easier than ever before with Xcode 12.5:
</p>
<ul>
<li>Open your iOS project in Xcode
<li>Navigate to File > Swift Packages > Add Package Dependency
<li>Insert the repository URL for Firebase (<a href="https://github.com/firebase/firebase-ios-sdk">https://github.com/firebase/firebase-ios-sdk</a>), and hit <em>enter</em> to install
<li>Once Xcode has resolved all the dependencies, choose the Firebase products you would like to use in your project
<li>Don't forget to download GoogleServices-Info.plist from your Firebase project and add it to your iOS project</li></ul>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-zX-1kJr4Ftc/YSbSZfe0JNI/AAAAAAAAFyU/R-qy0X5eM0w0rY05lTmfp_c9z9wuynW4ACLcBGAsYHQ/s0/CleanShot%2B2021-08-24%2Bat%2B15.41.34.gif" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="GIF showing how to add Firebase to iOS app" border="0" data-original-height="1125" data-original-width="2000" src="https://1.bp.blogspot.com/-zX-1kJr4Ftc/YSbSZfe0JNI/AAAAAAAAFyU/R-qy0X5eM0w0rY05lTmfp_c9z9wuynW4ACLcBGAsYHQ/s0/CleanShot%2B2021-08-24%2Bat%2B15.41.34.gif"/></a></div>
<h3>Heavy lifting</h3>
<p>
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 <a href="https://forums.swift.org/t/spm-support-for-binaries-distribution/25549">issues with binary libraries</a>, <a href="https://bugs.swift.org/browse/SR-2866">resource support</a>, and - last but not least - <a href="https://github.com/erikdoe/ocmock/issues/375">unit testing support</a>.
</p>
<p>
Performance Monitoring was the last Firebase product that was missing support for Swift Package Manager, and <a href="https://twitter.com/Firebase/status/1430621005186220036">just a few days ago</a>, 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%.
</p>
<h3>📦 Wrapping up</h3>
<p>
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.
</p>
<p>
We're working on updating the <a href="https://firebase.google.com/docs/ios/swift-package-manager">documentation</a>, setup flows, and <a href="https://github.com/firebase/quickstart-ios">quickstart apps</a> to reflect this change.
</p>
<p>
Come visit us on our <a href="https://github.com/firebase/firebase-ios-sdk/discussions">GitHub discussion board</a> and <a href="https://github.com/firebase/firebase-ios-sdk/issues">issue tracker</a>, and let us know what you think, or if you have any questions about migrating from CocoaPods to Swift Package Manager.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-72963454878991584752021-08-25T10:30:00.002-07:002021-08-25T10:41:42.536-07:00The new Firebase JS SDK is now GA<meta name="twitter:image" content="https://1.bp.blogspot.com/-y7HXMb3QEOU/YSVdD38MfaI/AAAAAAAAFxc/a3TblouBZCAmXd74ldR9b6wsfK2AroAXACLcBGAsYHQ/s0/size-table%2B%25282%2529.png">
<img style="display:none" src="https://1.bp.blogspot.com/-y7HXMb3QEOU/YSVdD38MfaI/AAAAAAAAFxc/a3TblouBZCAmXd74ldR9b6wsfK2AroAXACLcBGAsYHQ/s0/size-table%2B%25282%2529.png">
<figure class="profile">
<div class="profile-picture">
<img src="https://4.bp.blogspot.com/-wSmP7Jf6lQ4/VxfJYQMZJqI/AAAAAAAABLY/9pkWTtArIrIPoU_auQUcXZKLXWGWAw6WwCLcB/s1600/david_east.png" alt="David East">
</div>
<figcaption>
<strong><div>David East</div></strong>
<em>Developer Advocate</em>
</figcaption>
</figure>
<p>
<a href="https://github.com/firebase/firebase-js-sdk/issues/332#issue-276558629">You've asked for it</a>, 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.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-y7HXMb3QEOU/YSVdD38MfaI/AAAAAAAAFxc/a3TblouBZCAmXd74ldR9b6wsfK2AroAXACLcBGAsYHQ/s0/size-table%2B%25282%2529.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of code snippet with text that says A smaller Firebase" border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-y7HXMb3QEOU/YSVdD38MfaI/AAAAAAAAFxc/a3TblouBZCAmXd74ldR9b6wsfK2AroAXACLcBGAsYHQ/s0/size-table%2B%25282%2529.png"/></a></div>
<p>
As of today running <code>npm install firebase</code> 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 <a href="https://firebase.google.com/docs/web/modular-upgrade">upgrade guide</a> as well as our <a href="https://firebase.google.com/docs/web/module-bundling">guide to using the new SDK with module bundlers</a> for detailed guidance.
</p>
<p>
<strong>API changes for reduced size</strong>
</p>
<p>
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.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-vtRcdd0kZbk/YSVdYOLzvMI/AAAAAAAAFxk/eUOoFQ6c8x0L12MG3SWuw_yuMF3ELJTfgCLcBGAsYHQ/s0/tree-shaking%2B%25281%2529.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of code snippet with text that says Optimized for tree-shaking. Unused code elimination with bundlers like webpack, Rollup, esbuild, Parcel" border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-vtRcdd0kZbk/YSVdYOLzvMI/AAAAAAAAFxk/eUOoFQ6c8x0L12MG3SWuw_yuMF3ELJTfgCLcBGAsYHQ/s0/tree-shaking%2B%25281%2529.png"/></a></div>
<pre><code>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); });</code></pre>
<p>While this library organization is new, we have kept in place many familiar API concepts.</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-0kU_hjP38SU/YSVd8aTBfTI/AAAAAAAAFxs/ff22YcJcNoI6ppCsAMMebFcpnZKbf_bSACLcBGAsYHQ/s0/different-familiar-api%2B%25281%2529.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of code snippet with text that says A different, yet familiar API. Same functionality, lines of code, but 72 percent smaller." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-0kU_hjP38SU/YSVd8aTBfTI/AAAAAAAAFxs/ff22YcJcNoI6ppCsAMMebFcpnZKbf_bSACLcBGAsYHQ/s0/different-familiar-api%2B%25281%2529.png"/></a></div>
<pre><code>// 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); });</code></pre>
<p>
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 <strong>72% smaller</strong> than the version 8 example.
</p>
<p>
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.
</p>
<pre><code>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 => { });</code></pre>
<pre><code>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 => { });</code></pre>
<p>
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.
</p>
<p>
<strong>A compatibility library for an easier upgrade</strong>
</p>
<p>
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.
</p>
<p>
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.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-oYTBDnjaZOo/YSVehE5vcCI/AAAAAAAAFx0/AnYGCLKuRf0ckIIKvDeWmRbGzYGvgf3ugCLcBGAsYHQ/s0/compat%2B%25281%2529.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of code snippet with text saying Upgrade easily with compat" border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-oYTBDnjaZOo/YSVehE5vcCI/AAAAAAAAFx0/AnYGCLKuRf0ckIIKvDeWmRbGzYGvgf3ugCLcBGAsYHQ/s0/compat%2B%25281%2529.png"/></a></div>
<pre><code>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); });</code></pre><br>
<p>
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.
</p>
<p>
Once your code is fully upgraded, you can remove the compatibility library and begin to see any potential tree shaking benefits.
</p>
<p>
<strong>Introducing Firestore Lite</strong>
</p>
<p>
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.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-dLgBgajpgEQ/YSVe-kY65eI/AAAAAAAAFx8/4_L-CXtzp401XOrM0SdPJ1mZUsCmYAIBQCLcBGAsYHQ/s0/firestore-lite%2B%25281%2529.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of code snippet with text saying Firestore Lite" border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-dLgBgajpgEQ/YSVe-kY65eI/AAAAAAAAFx8/4_L-CXtzp401XOrM0SdPJ1mZUsCmYAIBQCLcBGAsYHQ/s0/firestore-lite%2B%25281%2529.png"/></a></div>
<pre><code>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'));</code></pre>
<p>
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.<br>
</p>
<p>
<strong>Moving away from the browser's global window object</strong>
</p>
<p>
Another significant development in the new SDK is the move towards JavaScript modules (ESM) and away from the browser's global <code>window</code> object.
</p>
<p>
Historically libraries have been loaded and managed via a namespace on the <code>window</code>, such as <code>window.firebase</code>. This technique does not allow for tree shaking and lacks other benefits of the JavaScript module system.
</p>
<p>
This release prioritizes usage of Firebase via JavaScript modules. We still provide support for the <code>window</code> via a CDN script for the compatibility library. However, we only recommend using it as a path to upgrading to the module based SDK.
</p>
<p>
<strong>Get started today</strong>
</p>
<center><iframe width="560" height="315" src="https://www.youtube.com/embed/rQvOAnNvcNQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></center>
<p>
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 <a href="https://github.com/firebase/firebase-js-sdk/discussions">GitHub discussion board</a> for any questions or comments. If you've seen any size reductions in your codebase and want to share, let us know!
</p>
Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-40558840188578774192021-08-18T10:00:00.001-07:002021-08-18T10:05:40.720-07:00Meet the Firestore Emulator Requests Monitor<meta name="twitter:image" content="https://1.bp.blogspot.com/-mj36T7yOcMA/YRvrozwZNBI/AAAAAAAAFwk/GFZJXsux9EY0a7px3Rbi1GBzwA-F_90OgCLcBGAsYHQ/s0/see%2Bevery%2Brequest.png">
<img style="display:none" src="https://1.bp.blogspot.com/-mj36T7yOcMA/YRvrozwZNBI/AAAAAAAAFwk/GFZJXsux9EY0a7px3Rbi1GBzwA-F_90OgCLcBGAsYHQ/s0/see%2Bevery%2Brequest.png">
<figure class="profile">
<div class="profile-picture">
<img src="https://3.bp.blogspot.com/-YWq7CXuPKN8/Xsa-amwRMCI/AAAAAAAAEwk/V7JDx71dgpceMJOwNdIkU13S_Qc00xT_QCLcBGAsYHQ/s1600/00100trPORTRAIT_00100_BURST20191201115729742_COVER_2.jpg" style="margin: 0 0 0 0;" data-original-width="600" data-original-height="600" />
</div>
<figcaption>
<strong><div>
Yuchen Shi</div>
</strong>
<em>Software Engineer</em>
</figcaption>
</figure>
<p>
The Firestore Emulator Requests Monitor allows you to see requests to your local <a href="https://firebase.google.com/docs/emulator-suite/connect_firestore ">Firestore Emulator</a> 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 <a href="https://firebase.googleblog.com/2020/05/local-firebase-emulator-ui.html">Emulator UI</a> if you have the latest Firebase CLI running. (If not, it's never too late to <a href="https://firebase.google.com/docs/cli#update-cli">upgrade</a>!)
</p>
<p>
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!
</p>
<h3>A New Requests View</h3>
<p>
First, <a href="https://firebase.google.com/docs/emulator-suite/connect_and_prototype#prototype_interactively">start the Emulator Suite</a>, 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.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-mj36T7yOcMA/YRvrozwZNBI/AAAAAAAAFwk/GFZJXsux9EY0a7px3Rbi1GBzwA-F_90OgCLcBGAsYHQ/s0/see%2Bevery%2Brequest.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of Firestore Emulator Suite with text saying See Every Request. Logs requests on any platform. Details are just one click away" border="0" data-original-height="311" data-original-width="512" src="https://1.bp.blogspot.com/-mj36T7yOcMA/YRvrozwZNBI/AAAAAAAAFwk/GFZJXsux9EY0a7px3Rbi1GBzwA-F_90OgCLcBGAsYHQ/s0/see%2Bevery%2Brequest.png"/></a></div>
<p>
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 <code>CREATE</code> 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.
</p>
<p>
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.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-NRvsAUChIws/YRvsaZbeKnI/AAAAAAAAFws/Dsaz6LHR-34j0hswJe4-N8EPPlsaLoO-ACLcBGAsYHQ/s0/inspect%2Brules.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of Firestore Emulator Suite Inspect Rules code snippet with text saying Inspect Rules. See passing or failing lines with populated in variables" border="0" data-original-height="311" data-original-width="512" src="https://1.bp.blogspot.com/-NRvsAUChIws/YRvsaZbeKnI/AAAAAAAAFws/Dsaz6LHR-34j0hswJe4-N8EPPlsaLoO-ACLcBGAsYHQ/s0/inspect%2Brules.png"/></a></div>
<p>
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 <code>resource</code>, the would-be version of the document (i.e. <code>request.resource</code>) 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.
</p>
<p>
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 <code>firebase.rules</code> 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.
</p>
<p>
For those of you who are familiar with the <a href="https://firebase.google.com/docs/rules/simulator">Security Rules Playground</a> 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 <em>should</em> 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.
</p>
<h3>Limitations</h3>
<p>
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 <a href="https://firebase.google.com/docs/firestore/security/rules-conditions#access_other_documents">depend on other documents</a> in the Firestore (e.g. <code>get(...)</code> or <code>exists(...)</code>), 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.
</p>
<p>
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 <em>not</em> 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.
</p>
<h3>Enjoy your new view into Firestore Emulator</h3>
<p>
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.
</p>
<p>
Feel free to play around with the Firestore Emulator Requests Monitor, and let us know what you think!
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-18703766728760100582021-08-13T10:00:00.016-07:002021-08-13T10:01:27.746-07:00Learn how Vinwap increased revenue by 30% in less than a week<meta name="twitter:image" content="https://1.bp.blogspot.com/-3Eae_1nkcNE/YRXHLYPi42I/AAAAAAAAFwU/t1n-vW10IqYHn16PtUsXu7Fmv9QPccuwwCLcBGAsYHQ/s0/Firebase-learn-how-vinwap-increased-revenue-social.png">
<img style="display:none" src="https://1.bp.blogspot.com/-3Eae_1nkcNE/YRXHLYPi42I/AAAAAAAAFwU/t1n-vW10IqYHn16PtUsXu7Fmv9QPccuwwCLcBGAsYHQ/s0/Firebase-learn-how-vinwap-increased-revenue-social.png">
<figure class="profile">
<div class="profile-picture">
<img style="margin:0;" border="0" src="https://1.bp.blogspot.com/-70P5f0fDXDY/XyHtd3BLrqI/AAAAAAAAE5k/FU72OIkD4VMHRwBm0njVwKwIhQKHrsSqACLcBGAsYHQ/s1600/0002_LauraWillis320.jpg" />
</div>
<figcaption>
<strong><div>
Laura Willis</div>
</strong>
<em>Developer Marketing</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-3Eae_1nkcNE/YRXHLYPi42I/AAAAAAAAFwU/t1n-vW10IqYHn16PtUsXu7Fmv9QPccuwwCLcBGAsYHQ/s0/Firebase-learn-how-vinwap-increased-revenue-social.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Firebase learn how vinwap increased revenue social" border="0" data-original-height="1027" data-original-width="2048" src="https://1.bp.blogspot.com/-3Eae_1nkcNE/YRXHLYPi42I/AAAAAAAAFwU/t1n-vW10IqYHn16PtUsXu7Fmv9QPccuwwCLcBGAsYHQ/s0/Firebase-learn-how-vinwap-increased-revenue-social.png"/></a></div>
<p>
Recently <a href="https://firebase.googleblog.com/2021/07/see-how-crazylabs-uses-firebase-remote-config-to-optimize-apps-at-scale.html">we shared the story of how CrazyLabs</a>, 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 <a href="https://firebase.google.com/docs/reference/remote-config/rest">Remote Config API</a>, Remote Config can also be a great tool for achieving fast results that have a direct impact on revenue.
</p>
<p>
<a href="https://play.google.com/store/apps/dev?id=8454145829299001834">Vinwap</a> is an indie developer who helps users personalize their Android devices with “live” wallpaper apps, including <a href="https://play.google.com/store/apps/details?id=com.vinwap.glitter">Glitter Live Wallpaper Glitzy</a> and <a href="https://play.google.com/store/apps/details?id=com.vinwap.parallaxpro">4D Parallax Wallpaper</a>. They use <a href="https://admob.google.com/">AdMob</a> 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.
</p>
<p>
Check out our latest <a href="https://firebase.google.com/use-cases/vinwap/">case study</a> 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.”
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-47578217471173120292021-08-12T10:28:00.001-07:002021-08-12T10:28:55.082-07:00Deep dive into the new Firebase JS SDK design<meta name="https://1.bp.blogspot.com/-bGgjVdRx154/YRRUfHwI7rI/AAAAAAAAFwM/TyfcMepSEHgMMRnGNlAR2TTOHpOIofY0QCLcBGAsYHQ/s0/js%2Bmodules.png">
<img style="display:none" src="https://1.bp.blogspot.com/-bGgjVdRx154/YRRUfHwI7rI/AAAAAAAAFwM/TyfcMepSEHgMMRnGNlAR2TTOHpOIofY0QCLcBGAsYHQ/s0/js%2Bmodules.png">
<figure class="profile">
<div class="profile-picture">
<img src="https://4.bp.blogspot.com/-wSmP7Jf6lQ4/VxfJYQMZJqI/AAAAAAAABLY/9pkWTtArIrIPoU_auQUcXZKLXWGWAw6WwCLcB/s1600/david_east.png" alt="David East">
</div>
<figcaption>
<strong><div>David East</div></strong>
<em>Developer Advocate</em>
</figcaption>
</figure>
<p>Firebase has kept a stable JavaScript interface for around 5 years now. If you wrote the following line of code 5 years ago, it would still work today.</p>
<pre><code>import firebase from 'firebase/app';
import 'firebase/auth';
firebase.initializeApp({ /* config */ });
const auth = firebase.auth();
auth.onAuthStateChanged(user => {
// Check for user status
});</code></pre>
<p>
No one wants to rewrite code for the sake of rewriting code. A stable experience is one of the top decision factors when you choose to invest in a library. We have always taken that seriously. Our dedication to a stable API has been an ongoing balance of maintaining existing patterns and adopting new techniques for a better performance and developer experience. But, as Firebase lands more features, the SDK itself becomes larger. In order <a href="https://www.youtube.com/watch?v=r5eJQ3nPc6A&t=1s">to reduce size and fit the modern web</a>, we <a href="https://firebase.googleblog.com/2021/07/introducing-the-new-firebase-js-sdk.html">decided to make changes</a> that required a break in our longstanding API.
</p>
<p>
<strong>A modular approach</strong>
</p>
<p>
When the original Firebase library was authored in 2012 the window was the only way to emulate a module system in the browser. It was a common practice to attach a "namespace" for your library on the window, hence window.firebase.
</p>
<p>
Today we have a native module system in the browser. We have a rich ecosystem of JavaScript module bundlers like <a href="https://rollupjs.org/guide/en/">Rollup</a> and <a href="https://webpack.js.org/">Webpack</a> that make it easy to efficiently package application code with library code. These tools work best when dealing with module based JavaScript code.
</p>
<p>
The benefit is an effect called "tree shaking", which has the ability to eliminate unused code from your application and the libraries you import.
</p>
<p>
Firebase is changing to follow a modular pattern that provides tree shaking and therefore better performance for your sites. This modular approach removes "side-effect" imports and isolates features as individual functions.
</p>
<p>
Take a look at the sample below.
</p>
<pre><code>import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
// Check for user status
});</code></pre>
<p>
In the snippet above there's a lot of new pieces, especially around the imports, but there's also a lot of familiarity. The biggest difference is the organization of the code. It all comes down to namespaces versus modules.
</p>
<p>
<strong>Namespaces and services</strong>
</p>
<p>
Firebase has been available as a JavaScript module for quite some time now. However, our commitment to backwards compatibility and a stable API has kept us from taking advantage of a module first approach. It's one thing to be used as a module, but it's another to actually be modular. Any library can work in a module system, but it takes a specific organization to get the benefits of modules.
</p>
<p>
Firebase has followed a namespace and service pattern.
</p>
<pre><code>const firestore = firebase.firestore();
const colRef = firestore.ref('cities');</code></pre>
<p>
In this sample firebase is a namespace that contains the firestore service. Other services like Firestore, Authentication, Remote Config, Realtime Database, and Messaging can all also live on the namespace. Each service is also a namespace as well. The firestore service has a set of methods attached, like <code>collection()</code>.
</p>
<p>
Organizing code in this way has its benefits. It's mentally easier for developers to "dot chain" to see what's available on a service. This approach was also easier to package before JavaScript had a bonafide module system. As JavaScript modules entered mainstream development, Firebase adapted but without breaking the namespace and service pattern. This kept the library stable but did not take full advantage of what JavaScript modules offer. Take the following code sample into account.
</p>
<pre><code>import firebase from 'firebase/app';
import 'firebase/auth';
firebase.initializeApp({ /* config */ });
const auth = firebase.auth();
auth.onAuthStateChanged(user => {
// Check for user status
});</code></pre>
<p>Let's go through the sample above, nearly line by line.</p>
<pre><code>import firebase from 'firebase/app';
import 'firebase/auth';</code></pre>
<p>
The code starts by importing the <code>firebase/app</code> and <code>firebase/auth</code> packages. Notice though that they're imported differently. The <code>firebase/app</code> package has an export that gives us methods like <code>initializeApp</code>. However, the <code>firebase/auth</code> package has no exports. This type of import has many names, but I'm going to refer to it as a side-effect import. The side-effect import does not have any exports and typically when used they augment something. What does that mean for Firebase in this example? That's the firebase export.
</p>
<pre><code>firebase.initializeApp({ /* config */ });
const auth = firebase.auth();</code></pre>
<p>
It's hard to tell what a side-effect import does knowing exactly what that importing <code>firebase/auth</code> does. In this case <code>firebase/auth</code> augments the <code>firebase</code> export from `firebase/app` and creates the `firebase.auth` namespace. If <code>firebase/auth</code> was not imported there would be an error when accessing <code>firebase/auth</code>.
</p>
<p>
The sample goes on to monitor a user's status.
</p>
<pre><code>auth.onAuthStateChanged(user => {
// Check for user status
});</code></pre>
<p>
The <code>onAuthStateChanged</code> method is available because of the side-effect import that augments the <code>firebase</code> export. But as a side-effect, the rest of the features offered by Firebase Authentication are on the namespace, whether you are using them or not. The current page may not handle any sign-in logic, but all 9 of Firebase Auth's sign-in methods will be included in your bundle. This is because of the namespace pattern.
</p>
<p>
The ability to chain methods off of the auth namespace is easy to understand and works well with IDEs that provide code completion like VSCode. It does not work well with tree shaking because no current tools are able to detect which methods on the chain are not used or what parts of a side-effect import are not needed. This leads to sites and apps that include more JavaScript than necessary. At Firebase we decided to reorganize our libraries in a modular pattern that supports tree shaking and therefore a smaller footprint in your site.
</p>
<p>
<strong>The new modular library</strong>
</p>
<p>
The new library moves away from the namespace approach and instead towards isolating features in JavaScript functions. Functions are a great way of organizing code and to promote tree shaking. Functions are independent units of code that take in arguments and return new values. Take a look at the new version of the sample code shown above.
</p>
<pre><code>import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
// Check for user status
});</code></pre>
<p>
The first thing to notice is that this sample is similar to one shown above. The first sample was eight lines of code, this sample is 8 lines of code. Both samples use two packages and accomplish the same objective: monitor authentication state.
</p>
<p>
Again, let's go through nearly line by line.
</p>
<pre><code>import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';</code></pre>
<p>
The side-effect imports are gone. The <code>firebase/auth</code> package provides exports rather than augmenting the <code>firebase</code> namespace. Another thing to note is there is no longer a <code>firebase</code> namespace. The <code>firebase/app</code> package does not return a "catch-all" export that contains all the methods from the package. Instead the package exports individual functions. Tree shaking tools like Rollup know that if a function isn't used it doesn't get included in the final build. This is unlike the firebase namespace or side-effect import in the previous sample. Build tools have to include everything when code is organized in that fashion.
</p>
<p>
The ergonomics of functions are different from a namespace with a bunch of methods attached to it. This is where the new organization really starts to show.
</p>
<pre><code>const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);</code></pre>
<p>
The main difference in the lines above is that there is no more chaining from <code>firebaseApp.auth()</code>. Instead there is a <code>getAuth()</code> function that takes in <code>firebaseApp</code> and returns an auth instance. This may seem strange at first, but it provides more clarity than a side-effect import. Previously, the side-effect import augmented the firebase namespace behind the scenes. It was not clear how an auth service was created and it did not allow for tree shaking. The <code>getAuth()</code> function returns an initialized auth service from the details needed from the <code>firebaseApp</code>. This is a clear process: call a function with an argument, get a result back.
</p>
<p>
Creating a service this way allows the rest of the features of the library to be tree shake-able as well. Methods are no longer chained. Services are passed as the first argument and the function then uses the details of the auth service to do the rest. The rest of the functions in the <code>firebase/auth</code> package work this way as well. The auth service is the first argument and then what specific function needs next. Passing the auth service allows the other functions to use the details they need without needing a "catch-all" service that contains all the methods.
</p>
<p>
This new modular approach strips out unused code and builds upon modern web features.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-DhQkZkNftcg/YRP_tyiceWI/AAAAAAAAFwE/hYWPnnGYlVAtxl1h0F8LDNao_fIEi-7GwCLcBGAsYHQ/s0/A%2Bsmaller%2BFirebase.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image with text saying A Smaller Firebase with code snippet below" border="0" data-original-height="320" data-original-width="512" src="https://1.bp.blogspot.com/-DhQkZkNftcg/YRP_tyiceWI/AAAAAAAAFwE/hYWPnnGYlVAtxl1h0F8LDNao_fIEi-7GwCLcBGAsYHQ/s0/A%2Bsmaller%2BFirebase.png"/></a></div>
<p>
<strong>Upgrade one library at a time</strong>
</p>
<p>
We fully understand that this upgrade is a breaking change which requires you to update existing code. As you would imagine, we have a lot of code internally that uses the Firebase JavaScript library as well. We understood this pain point immediately and created the compatibility library.
</p>
<p>
The compatibility library provides you the same API as the previous library version (version 8), but uses the new version 9 library under the hood. This allows you to use the new API and the old at the same time as you upgrade your site.
</p>
<p>
The ability to use these APIs side by side gives you flexibility when upgrading.
</p>
<pre><code>import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
const firebaseApp = firebase.initializeApp({ /* config */ });
const auth = firebaseApp.auth();
auth.onAuthStateChanged(user => {
// Check for user status
});</code></pre>
<p>
The first thing to notice is that the only change needed was to change the import paths to the <code>/compat/</code> entry point. From here you can add the new libraries.
</p>
<pre><code>import firebase from 'firebase/compat/app';
import { getAuth } from 'firebase/auth';
import 'firebase/compat/auth';
const firebaseApp = firebase.initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
auth.onAuthStateChanged(user => {
// Check for user status
});</code></pre>
<p>In the snippet above, both Firebase Auth library versions are being used. This code works and builds just fine. However, we don't recommend you use both versions unless you are in the middle of an upgrade.</p>
<pre><code>import firebase from 'firebase/compat/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
const firebaseApp = firebase.initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
// Check for user status
});</code></pre>
<p>
The last step you'll take when upgrading is to upgrade <code>firebase/app</code>. While upgrading you will need to keep the namespace import from the <code>firebase/compat/app</code> library until each Firebase service has been upgraded to the new version.
</p>
<pre><code>import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
// Check for user status
});</code></pre>
<p>
Once everything is upgraded, you won't have any dependencies left on the compatibility library and you'll start to see the full tree shakeable benefits.
</p>
<p>
<strong>Let us know what you think!</strong>
</p>
<p>
We are really excited about the future of this library and the performance benefits it can provide. This library is still in beta and we want to know what you think of these changes. Come visit us on our <a href="https://github.com/firebase/firebase-js-sdk/discussions">GitHub discussion board</a> and let us know what you think, if you're seeing size reductions in your bundles or if you have any questions about upgrading.
</p>
Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-87637802371718075132021-08-03T10:00:00.001-07:002021-08-03T10:00:00.227-07:00New features in App Check beta<meta name="https://1.bp.blogspot.com/-3LHAqIOYnr4/YQgZ_HtgCWI/AAAAAAAAFu0/wRAzr09XB7Q4nG1zU5c_86b2DIVESgLQQCLcBGAsYHQ/s0/app%2Bcheck%2Bheader.png">
<img style="display:none" src="https://1.bp.blogspot.com/-3LHAqIOYnr4/YQgZ_HtgCWI/AAAAAAAAFu0/wRAzr09XB7Q4nG1zU5c_86b2DIVESgLQQCLcBGAsYHQ/s0/app%2Bcheck%2Bheader.png">
<figure class="profile">
<div class="profile-picture">
<img alt=""
src=" https://1.bp.blogspot.com/-2sf21zMVFQI/X5hzhhZ3USI/AAAAAAAAFQw/O1YcXxJ5wqkKefqLT2pT8bLTI_3p-bh0QCLcBGAsYHQ/s0/unnamed%2B%25281%2529.jpg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Tyler Crowe </div>
</strong>
<em> Product Manager </em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-3LHAqIOYnr4/YQgZ_HtgCWI/AAAAAAAAFu0/wRAzr09XB7Q4nG1zU5c_86b2DIVESgLQQCLcBGAsYHQ/s0/app%2Bcheck%2Bheader.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Image of 6 illustrated people holding electronic devices" border="0" data-original-height="720" data-original-width="1280" src="https://1.bp.blogspot.com/-3LHAqIOYnr4/YQgZ_HtgCWI/AAAAAAAAFu0/wRAzr09XB7Q4nG1zU5c_86b2DIVESgLQQCLcBGAsYHQ/s0/app%2Bcheck%2Bheader.png"/></a></div>
<p>
A few months ago, at Google I/O, we announced the beta of App Check, Firebase’s new mobile and web API security solution. App Check is an additional layer of security that protects access to your services by attesting that incoming traffic is coming from your app, and blocking traffic that doesn't have valid credentials. Right now, App Check is available for Cloud Storage, Realtime Database, and Cloud Functions for Firebase. In case you missed the launch, check out our introduction video to see <a href="https://www.youtube.com/watch?v=Fjj4fmr2t04">how App Check works</a>.
</p>
<p>
Today, we’re happy to announce three new features we’ve added to the App Check beta: support for App Attest on iOS, configurable time-to-live values (TTLs) for tokens, and support for protecting non-Firebase backends with App Check.
</p>
<h2>App Attest</h2>
<p>
We know how important security is, so we wanted to make sure we’re integrated with the latest app attestation providers for our main platforms, and that includes iOS. To that end, we’ve added support on iOS for App Attest, Apple’s app attestation technology that was recently <a href="https://developer.apple.com/videos/play/wwdc2021/10244/">featured at Apple’s WWDC conference</a>.
</p>
<p>
App Attest can be used to assert that a request comes from a legitimate instance of your app that satisfies three conditions:
</p>
<ul>
<li>The request comes from a genuine Apple device.
<li>The device is running your genuine application.
<li>The payload has not been tampered with.
</li>
</ul>
<p>
You can use App Attest as an App Check provider on any iOS device that supports it. On devices without App Attest support, you can continue to use DeviceCheck with App Check. See our developer guide to learn how to <a href="https://firebase.google.com/docs/app-check/ios-app-attest">use App Check with App Attest on iOS</a>.
</p>
<h2>Configurable TTLs</h2>
<p>
To give you the power to choose how you want to balance security and usability in your app, we’ve added the optional ability to set the TTL of App Check tokens. By using a short TTL, you optimize for increased security; on the other hand, a longer TTL can improve responsiveness and minimize quota usage. You can even customize the TTL individually per attestation provider. Configurable TTLs are supported when using App Attest, Device Check, SafetyNet, reCAPTCHA v3, and custom providers.
</p>
<h2>Protecting your own server with App Check</h2>
<p>
If you use your own backend services alongside Firebase, App Check can still help you! With our newest beta, you can protect your non-Firebase resources with App Check. This protection is currently possible on any backend service or service proxy that can run the Firebase Admin SDK for Node.js, including Cloud Run & GKE instances, and even bare metal servers.
</p>
<p>
If you already use App Check with RTDB, Storage or Functions, it is now really easy to extend App Check’s protections to your own server as well. It only takes a few lines of code on the client and on the backend to start protecting your resources today. Take a look at our guides for <a href="https://firebase.google.com/docs/app-check/ios/custom-resource">iOS</a>, <a href="https://firebase.google.com/docs/app-check/android/custom-resource">Android</a>, and <a href="https://firebase.google.com/docs/app-check/web/custom-resource">web</a> to learn how.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-11137814770046394552021-08-02T12:45:00.003-07:002022-03-09T12:09:59.812-08:00Unlocking your app’s best experience with Firebase Performance Monitoring<meta name="twitter:image" content="https://1.bp.blogspot.com/-yMpiQDlQmcc/YQgk017DPFI/AAAAAAAAFvA/_35kVpxnpvM6KqSRXRNMhe-2B0Hbl8SvgCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_header.png">
<img style="display:none" src="https://1.bp.blogspot.com/-yMpiQDlQmcc/YQgk017DPFI/AAAAAAAAFvA/_35kVpxnpvM6KqSRXRNMhe-2B0Hbl8SvgCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_header.png">
<figure class="profile">
<div class="profile-picture">
<img alt=""
src=" https://1.bp.blogspot.com/-uEMhHq_fL6o/YQgkm_AmoSI/AAAAAAAAFu8/4G986Pa0TVAPQfIwuzlKfflCf9SGGdBgACLcBGAsYHQ/s0/Nitin_Pic.jpeg" style="margin: 0px 0px 10px 0%;" />
</div>
<figcaption>
<strong><div>
Nitin Kaushik</div>
</strong>
<em> Engineering Manager </em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-yMpiQDlQmcc/YQgk017DPFI/AAAAAAAAFvA/_35kVpxnpvM6KqSRXRNMhe-2B0Hbl8SvgCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_header.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Firebase Performance Monitoring Header" border="0" data-original-height="632" data-original-width="1600" src="https://1.bp.blogspot.com/-yMpiQDlQmcc/YQgk017DPFI/AAAAAAAAFvA/_35kVpxnpvM6KqSRXRNMhe-2B0Hbl8SvgCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_header.png"/></a></div>
<p><strong>This is part of a series of articles about app quality. Here is an overview of all the other articles:</strong></p>
<ul>
<li><a href="https://firebase.googleblog.com/2021/07/the-firebase-guide-to-building-stable-high-performing-apps.html">The Firebase guide to building stable, high-performing apps</a>
<li><a href="https://firebase.googleblog.com/2021/07/unlocking-next-level-of-app-stability-with-firebase-crashlytics.html">Unlocking the next level of app stability with Firebase Crashlytics</a></li></ul>
<p>
Apps and games have evolved rapidly in recent years, and user expectations for high performance have increased right alongside them. Today’s users don’t just demand speed and performance — they reward it. A <a href="https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/mobile-page-speed-data/">2019 study</a> found that retail sites saw 8% more conversions when they reduced their mobile site load times by one-tenth of a second. And travel sites boosted conversions by just over 10%.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-mMyCrv1tj1U/YQglGUZ_Y2I/AAAAAAAAFvM/I7m-DVstn44DOgxWpxLo5dspTPx3zARnACLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_1.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="Graphic showing 8% increase in conversions for retail" border="0" data-original-height="500" data-original-width="1600" src="https://1.bp.blogspot.com/-mMyCrv1tj1U/YQglGUZ_Y2I/AAAAAAAAFvM/I7m-DVstn44DOgxWpxLo5dspTPx3zARnACLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_1.png"/></a></div>
<p>
As you reach more users across different devices, locations, OS versions, and networks, optimizing performance becomes even more of a moving target. To understand the unique context behind performance issues, you need actionable insights about your app performance from a user's perspective. With performance data that allows you to spend less time putting out fires, you can devote more time to creating delightful experiences knowing that no bug or glitch will slip through the cracks.
</p>
<p><strong><em>With performance data that allows you to spend less time putting out fires, you can devote more time to creating delightful experiences knowing that no bug or glitch will slip through the cracks.</em></strong>
</p>
<p>In this article, we’ll explore some Firebase Performance Monitoring features that can help you keep an eye on your app’s performance and understand the experience from a user's point of view.</p>
<p>
<strong>Real-time app performance metrics</strong>
</p>
<p>
Releasing a new feature that performs well for every user — no matter their location, device, or network speed — can be challenging if you don’t have the timely information you need to gauge performance across a range of variables. When poor performance and low app ratings occur, you need clear insights to deliver an experience worthy of a 5-star review.
</p>
<p>
<a href="https://firebase.google.com/products/performance">Firebase Performance Monitoring</a> processes your app performance data in real time so you can monitor new releases during development and post-launch. For instance, you can gather performance data from <a href="https://firebase.google.com/docs/emulator-suite">Firebase Emulators</a> or virtual devices on <a href="https://firebase.google.com/docs/test-lab">Firebase Test Lab</a> to test your app locally before launch. And after launch, you can get insights about metrics related to screen rendering and network requests to learn how your app is performing among different user segments.
</p>
<p>By learning how your app responds for different groups of users, you can quickly take action to fix any errors and ensure users won’t delete your app to find one that works better on their device.</p>
<a href="https://1.bp.blogspot.com/-d8q1Zb-7qRU/YQgl-H3gCvI/AAAAAAAAFvU/J1iHKNkxgQs5hhxOnXC_oASmmugW8LYXwCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_3.png" imageanchor="1" ><img id=imgFull alt="Performance Monitoring dashboard highlighting real-time metrics" border="0" src="https://1.bp.blogspot.com/-d8q1Zb-7qRU/YQgl-H3gCvI/AAAAAAAAFvU/J1iHKNkxgQs5hhxOnXC_oASmmugW8LYXwCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_3.png" data-original-width="1058" data-original-height="714" /></a>
<p id="imgCaption">Performance Monitoring dashboard highlighting real-time metrics</p>
<p>
<strong>Customizable Metrics Board</strong>
</p>
<p>
In the <a href="https://firebase.googleblog.com/2021/07/the-firebase-guide-to-building-stable-high-performing-apps.html">first blog post</a> of this series, we highlighted some standard app performance metrics to keep top-of-mind, such as app start-up time, screen rendering performance, and network performance. However, sometimes the influx of real-time data after a big release can feel overwhelming, and identifying where you should focus and take action can be a daunting task.
</p>
<p>
With the <a href="https://firebase.google.com/docs/perf-mon/console?platform=android">revamped Performance Monitoring dashboard</a>, you can customize your app performance metrics board to highlight the most important metrics for your app. For example, if you’re releasing updates on a shopping app, you can select and track slow-rendering frames on the checkout screens. This helps ensure your customers are enjoying a seamless experience from start to finish. You can also break down your key metrics by country, device, app versions, and OS level for a deeper dive into your performance data.
</p>
<p>
<strong>By learning how quickly your app responds for different groups of users, you can take action to fix latency issues and ensure users won’t delete your app to find one that works better on their device.</strong>
</p>
<p>
Additionally, Performance Monitoring allows you to implement <a href="https://firebase.google.com/docs/perf-mon/custom-code-traces">custom code traces</a>, which help monitor the performance of your app between two points in time. You can also create your own traces to capture performance data associated with specific code in your app. For example, you could use custom code traces to measure how long it takes your app to load a set of images and make sure the graphics aren’t causing too much lag.
</p>
<p>
<strong>Compare performance between app versions </strong>
</p>
<p>
Retaining a diverse user base isn’t easy without understanding how specific user segments are engaging with your app — especially when their experience isn’t up to par. To make sure every new release performs at its best once it reaches a large number of users, you can use the new Performance Monitoring dashboard to identify app performance changes that need immediate attention.
</p>
<p>
The metrics board enables metric performance tracking across versions. If your latest release calls a new API at start-up, you can track latencies in app start time between the latest version of your app and previous versions. The traces table is especially helpful to understand how your traces are trending across selected time ranges. That means you no longer have to wait for app store reviews or support tickets to know when your app performance is lagging.
</p>
<a href="https://1.bp.blogspot.com/-X2YQfuk2b4M/YQgwGw2RgDI/AAAAAAAAFvc/NKdWW4mHawcX38gAe3vQTRahvxweCEcpQCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_4.png" imageanchor="1" ><img id=imgFull alt="Performance Monitoring traces table" border="0" src="https://1.bp.blogspot.com/-X2YQfuk2b4M/YQgwGw2RgDI/AAAAAAAAFvc/NKdWW4mHawcX38gAe3vQTRahvxweCEcpQCLcBGAsYHQ/s0/Firebase_PerformanceMonitoring_4.png" data-original-width="1058" data-original-height="714" /></a>
<p id="imgCaption">Performance Monitoring traces table</p>
<p>
<strong>Track trends, regressions, and severe issues</strong>
</p>
<p>
One of the most important ways to grow and engage your audience is by constantly releasing new features and updates to your app. But any code or configuration changes to your app or any of its many dependencies carry a risk of degrading your app’s performance or causing issues with user experience. For example, if your e-commerce app makes dozens of API calls to fetch your catalog and product details, users might experience frustrating lags during their shopping experience.
</p>
<p>
By tracking trends and regressions with Performance Monitoring, you can quickly act on the most critical issues and get ahead of low ratings on the app store.
</p>
<p>
<strong>Improve user retention with Performance Monitoring </strong>
</p>
<p>
<a href="https://firebase.google.com/use-cases/gamenexa/">GameNexa Studios</a>, an India-based app developer, seized an opportunity to invest in improving its app quality when their ad sales were disrupted by COVID-19. By combining Firebase Performance Monitoring and Firebase Crashlytics, the team gained actionable insights about its user base and improved their most popular app’s experience across the board. And by reducing the number of performance issues affecting its users, GameNexa ended up boosting both user retention and session duration, and increased in-app purchases by 2.5X.
</p>
<p>
<strong>Stay ahead of app stability and performance issues</strong>
</p>
<p>
To deliver the fast, consistent experience app that users expect, you need a strategy backed by tools that help you act quickly and fix significant issues on the fly. With detailed, actionable data and insights from Firebase, app developers and product managers can make smarter decisions before launch, tackle urgent issues swiftly after releasing an update, and quickly and confidently roll out new features that keep users coming back.
</p>
<p>
To get started with Firebase Performance Monitoring, integrate the <a href="https://firebase.google.com/docs/perf-mon">Performance Monitoring SDK</a> into your app and identify the metrics that matter most to your app’s success.
</p>
Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-71968386338231194872021-07-28T10:00:00.001-07:002021-07-28T10:00:00.168-07:00See how CrazyLabs uses Firebase Remote Config to optimize apps at scale<meta name="https://1.bp.blogspot.com/-VJUhPDselQA/YQBSRhfSFWI/AAAAAAAAFuU/pRCeArqY57klZoZl16Rcb6OHWj2aZ_cbACLcBGAsYHQ/s0/CrazyLabs-Case-Study-v1.png">
<img style="display:none" src="https://1.bp.blogspot.com/-VJUhPDselQA/YQBSRhfSFWI/AAAAAAAAFuU/pRCeArqY57klZoZl16Rcb6OHWj2aZ_cbACLcBGAsYHQ/s0/CrazyLabs-Case-Study-v1.png">
<figure class="profile">
<div class="profile-picture">
<img style="margin:0;" border="0" src="https://1.bp.blogspot.com/-70P5f0fDXDY/XyHtd3BLrqI/AAAAAAAAE5k/FU72OIkD4VMHRwBm0njVwKwIhQKHrsSqACLcBGAsYHQ/s1600/0002_LauraWillis320.jpg" />
</div>
<figcaption>
<strong><div>
Laura Willis</div>
</strong>
<em>Developer Marketing</em>
</figcaption>
</figure>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-VJUhPDselQA/YQBSRhfSFWI/AAAAAAAAFuU/pRCeArqY57klZoZl16Rcb6OHWj2aZ_cbACLcBGAsYHQ/s0/CrazyLabs-Case-Study-v1.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="image of Firebase logo and CrazyLabs logo" border="0" data-original-height="1024" data-original-width="2048" src="https://1.bp.blogspot.com/-VJUhPDselQA/YQBSRhfSFWI/AAAAAAAAFuU/pRCeArqY57klZoZl16Rcb6OHWj2aZ_cbACLcBGAsYHQ/s0/CrazyLabs-Case-Study-v1.png"/></a></div>
<p>
If you’ve used <a href="https://firebase.google.com/products/remote-config">Firebase Remote Config</a>, then you know how it can help you control and optimize your app on the fly. And <a href="https://firebase.googleblog.com/2021/05/whats-new-from-firebase-at-google-io.html#Remote">recent improvements</a> help you better visualize your configuration so you can more easily update your app to drive the outcomes you want, like <a href="https://firebase.google.com/use-cases/mobills">increasing subscription sign-ups</a>. But what if you have a portfolio of many apps that you want to optimize at the same time?
</p>
<p>
That was the goal of <a href="https://www.crazylabs.com/">CrazyLabs</a>, a hypercasual and casual publisher whose games, including <a href="https://play.google.com/store/apps/details?id=com.cocoplay.fashion.style">Super Stylist - Makeover & Style Fashion Guru</a>, <a href="https://play.google.com/store/apps/details?id=com.crazylabs.tie.dye.art&hl=en&gl=US">Tie Dye</a>, and <a href="https://play.google.com/store/apps/details?id=com.newnormalgames.phonecasediy&hl=en&gl=US">Phone Case</a> have been downloaded more than 4 billion times. Their business model relies on identifying potentially high-profit games early on among many applicants and helping them scale. CrazyLabs needed a solution that could help them test up to 30 configurations per title across up to 15 titles at a time in order to increase revenue without decreasing user engagement.
</p>
<p>
</p>
<p>
Learn how CrazyLabs used Remote Config and <a href="https://admob.google.com/home/">AdMob</a> to optimize monetization at scale for all of their titles in our <a href="https://firebase.google.com/use-cases/crazylabs">new case study</a>.
</p>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.comtag:blogger.com,1999:blog-4191548740220130749.post-36700149383988364482021-07-27T13:00:00.002-07:002021-07-27T13:02:57.663-07:00Introducing the new Firebase JS SDK
<figure class="profile">
<div class="profile-picture">
<img src="https://4.bp.blogspot.com/-wSmP7Jf6lQ4/VxfJYQMZJqI/AAAAAAAABLY/9pkWTtArIrIPoU_auQUcXZKLXWGWAw6WwCLcB/s1600/david_east.png" alt="David East">
</div>
<figcaption>
<strong><div>David East</div></strong>
<em>Developer Advocate</em>
</figcaption>
</figure>
<p>
Get ready for a new faster web experience with Firebase. For the longest time you all have asked us to optimize the size of our JavaScript libraries, and we've done just that. We've released brand new beta libraries that are significantly smaller in size. Some are even up to 80% smaller! We've managed to reduce the size all without removing any features from the previous version too!
</p>
<p>
How did we do this? We did it by embracing the modern web and its new features. We converted our library to take advantage of code elimination features of modern day JavaScript tools like webpack and Rollup. While this change drops size, it did require us to change the library's API for these tools to identify which functionality isn't being used in your app.</p>
<p><em><strong>This is a breaking change that will require you to update your code.</strong></em> We have released the library to npm under the <code>beta</code> tag, but we will be publishing it to the main tag in the near future. You can get started today and use the compatibility library to make the upgrade easier.
</p>
<p>
<strong>The new API</strong>
</p>
<p>
Take a look at our new beta API. The first thing you might notice is that we've removed all side-effect imports. You know, the <code>import firebase/<service></code> lines of code, which aren't very clear about what <em>exactly</em> is being imported. Or as <a href="https://webpack.js.org/guides/tree-shaking/#:~:text=A%20%22side%20effect%22%20is%20defined%20as%20code%20that%20performs%20a%20special%20behavior%20when%20imported%2C%20other%20than%20exposing%20one%20or%20more%20exports.%20An%20example%20of%20this%20are%20polyfills%2C%20which%20affect%20the%20global%20scope%20and%20usually%20do%20not%20provide%20an%20export">webpack succinctly puts it</a> <em>"A "side effect" is defined as code that performs a special behavior when imported, other than exposing one or more exports. An example of this are polyfills, which affect the global scope and usually do not provide an export."</em>
</p>
<p>
From now on in our API, we explicitly export each function from the package, which makes it clear what you are consuming in your app.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-IPsGsTULIf8/YP7kW-HbZ3I/AAAAAAAAFtc/2EfdfEIZNdIQrS0sklkGi2Ml9J7XrDJlACLcBGAsYHQ/s0/javascript-modules.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="An illustration titled JavaScript Modules. No more side-effect imports. Directly import what you need. Followed by a code terminal with the code sample below." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-IPsGsTULIf8/YP7kW-HbZ3I/AAAAAAAAFtc/2EfdfEIZNdIQrS0sklkGi2Ml9J7XrDJlACLcBGAsYHQ/s0/javascript-modules.png"/></a></div>
<pre><code>import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth();
onAuthStateChanged(auth, user => { console.log(user); });</code></pre>
<p>This new API has a lot of familiar functions from the previous one. The main difference is the organization of the code. We've removed all side-effect imports and created individual entry points for each and every package.</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-zZ8C0GscMT8/YP710Xw6w4I/AAAAAAAAFtk/xJ3spYxAvl8hZGEmY_FigMIgm6JBqeCEQCLcBGAsYHQ/s0/individual-entry-points.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="An illustration titled Individual entry points. No more side-effect imports. Followed by a code terminal with the code sample below." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-zZ8C0GscMT8/YP710Xw6w4I/AAAAAAAAFtk/xJ3spYxAvl8hZGEmY_FigMIgm6JBqeCEQCLcBGAsYHQ/s0/individual-entry-points.png"/></a></div>
<pre><code>import { initializeApp } from 'firebase/app';
import { getFirestore, collection, getDocs } from 'firebase/firestore';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
import { getStorage, uploadBytes } from 'firebase/storage';
import { getRemoteConfig, fetchAndActivate } from 'firebase/remote-config';
import { getRemoteConfig, fetchAndActivate } from 'firebase/remote-config';
import { getDatabase, ref, get } from 'firebase/database';
import { getMessaging, getToken } from 'firebase/messaging';
import { getPerformance } from 'firebase/performance';
import { getAnalytics, logEvent } from 'firebase/analytics';</code></pre>
<p>Modern JavaScript tools like webpack and Rollup discourage the use of side-effect imports. This is because side-effect imports are like an unknown quantity. Module bundlers don't know what they are going to bring in. Having explicit functions to import gives these tools a better understanding of how to build your code.</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-uLgRhG_MP1g/YP72stIr1SI/AAAAAAAAFts/xW6CuIxqPpsiDGMGhqRkTYty3TxmavYIwCLcBGAsYHQ/s0/tree-shaking.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="An illustration titled Optimized for tree-shaking. Dead code elimination with bundlers like webpack, Rollup, esbuild, Parcel. Followed by a code terminal with the code sample below." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-uLgRhG_MP1g/YP72stIr1SI/AAAAAAAAFts/xW6CuIxqPpsiDGMGhqRkTYty3TxmavYIwCLcBGAsYHQ/s0/tree-shaking.png"/></a></div>
<pre><code>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); });</code></pre>
<p>
When these tools can understand your code they can eliminate unused parts of a codebase, this is a feature called tree-shaking. This is what makes the new library so much smaller. By reorganizing the Firebase library we can take advantage of tree-shaking and remove all unneeded parts of the library from your app. This size savings we have seen have been significant.
</p>
<p>
<strong>How much smaller is the new library?</strong>
</p>
<p>
Let's get real for a second and talk library size. Firebase has always been a larger library on the web. The web itself is a balance of features and performance and we wanted to make that balance a lot easier for you. This was the biggest reason for us to take on tree shaking. We suspect that no matter what you'll see a sizable drop in your bundle size. However, we're hoping that with specific use cases you'll see significant size reductions.
</p>
<p>
The two biggest areas of improvement we have seen in our early studies are with the new <code>firebase/firestore/lite</code> package (more on that in a bit!) and <code>firebase/auth</code>. The table below shows a package, the current SDK version size, the current beta version size for a basic use case, and the percentage the SDK is lighter than the current v8 version.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Cpu1GI8J9M0/YP73W6JSxwI/AAAAAAAAFt0/oqk1jrU7ZX4_znVJyrBCGadb2wGKIld_wCLcBGAsYHQ/s0/size-table.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="An illustration titled A smaller Firebase. 8.7.1 vs 9.0.0-beta.6. Followed by a code terminal with the code sample below." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-Cpu1GI8J9M0/YP73W6JSxwI/AAAAAAAAFt0/oqk1jrU7ZX4_znVJyrBCGadb2wGKIld_wCLcBGAsYHQ/s0/size-table.png"/></a></div>
<p>
You'll notice that authentication can be up to 72% lighter than before. When using <code>firebase/firestore/lite</code> you can save 84% from the current version of <code>firebase/firestore</code> if you only need one-time reads. This new "import only what you need" method allows you to decide what to include in your bundles and make that features and performance balance much easier.
</p>
<p>
<strong>Introducing Firestore Lite</strong>
</p>
<p>
Firestore is such a powerful library because it does so many things behind the scenes that we encourage you all to take for granted. Firestore has a complex caching, realtime streaming, persistent storage, multi-tab offline sync, retries, optimistic concurrency, and so much more. But we heard from you all that sometimes you just need to get a collection, and don't want to include all of Firestore's other features in your site. For those cases we wanted to make Firestore a simple and light solution, so we created a brand new subpackage: <code>firebase/firestore/lite</code>.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-1DdN6OKJ59w/YP73m_vNmgI/AAAAAAAAFt8/dBWYmb5zS1Qz0VZHsQaG3PCaoBsMd7rtACLcBGAsYHQ/s0/firestore-lite.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="An illustration titled Firestore Lite. A small, REST-based client library. Followed by a code terminal with the code sample below." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-1DdN6OKJ59w/YP73m_vNmgI/AAAAAAAAFt8/dBWYmb5zS1Qz0VZHsQaG3PCaoBsMd7rtACLcBGAsYHQ/s0/firestore-lite.png"/></a></div>
<pre><code>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'));</code></pre>
<p>
This sample uses <code>firebase/app</code> and the new firebase/firestore/lite package. You'll notice that calling <code>getDocs()</code> initiates a one-time data read. Firestore Lite allows you to create, read, update, and delete data with Firestore in a much smaller library. Realtime streaming is not included, but you can always switch back to <code>firebase/firestore</code> if that's what you need. If you want to adopt an advanced loading strategy, you can even load <code>firestore/lite</code> for a fast initial page load and lazy load <code>firebase/firestore</code> for progressive enhancement.
</p>
<p>
Firestore Lite is significantly smaller. As you saw in the table above, it can be 84% lighter. We know that you Firestore users will find a great fit for this library.
</p>
<p>
<strong>An easier upgrade with our compatibility library</strong>
</p>
<p>
Change is never easy. Our new library provides new benefits but it's hard to go back and rewrite code that already works. To make that process easier, we're also releasing a compatibility library that allows you to port your code piece by piece.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-8xGq459Iy3U/YP74cVsk5yI/AAAAAAAAFuE/afh3VVTHKt8xzqY-sZGO0cRFrSgh02UHwCLcBGAsYHQ/s0/compat.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="An illustration titled Upgrade easily with compat. Import firebase/compat/<service>. Followed by a code terminal with the code sample below." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-8xGq459Iy3U/YP74cVsk5yI/AAAAAAAAFuE/afh3VVTHKt8xzqY-sZGO0cRFrSgh02UHwCLcBGAsYHQ/s0/compat.png"/></a></div>
<pre><code>import { initializeApp } from 'firebase/compat/app';
import 'firebase/auth/compat';
import { onAuthStateChanged } from 'firebase/auth';
const firebaseApp = firebase.initializeApp({ /* config */ });
const auth = firebaseApp.auth();
onAuthStateChanged(auth, user => { console.log(user); });</code></pre>
<p>
The new modular SDK cannot be used alongside the existing namespace based library, but the compatibility library allows you to use both APIs <em>at the same time</em>. You won't get all of the tree shaking advantages upfront, but once you match the new modular library you can switch off the compatibility library and rake in the savings.
</p>
<p>
<strong>What about framework integrations?</strong>
</p>
<p>
Libraries like <a href="https://github.com/angular/angularfire/pull/2770">AngularFire</a>,<a href="https://github.com/FirebaseExtended/reactfire/pull/369"> ReactFire</a>, and <a href="https://github.com/FirebaseExtended/rxfire/pull/1">RxFire</a> will be compatible with the new SDK in the near future. We are close to completing them, so hang tight! Track their progress in these issues on GitHub.
</p>
<p>
Once they have been updated there will be little to no work to move over, as we will update them underneath the hood. However, AngularFire will not initially receive all of the tree shaking benefits since it follows a classical OOP structure. We plan on releasing an API proposal in the near future to optimize for tree shaking and provide an easy path to upgrade as well.
</p>
<p>
<strong>Get started today</strong>
</p>
<p>
The new JavaScript library is available today on npm under the <code>beta</code> tag. We want to hear your feedback! Tell us what you think of the new API and any size savings you've seen. We're excited about the future of this library and the performance benefits it brings.
</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-j0BPRRXIP14/YP74x5VG_oI/AAAAAAAAFuM/ILPM0YF4TsIjodgiDKE3Ua5CXrjSjCsSACLcBGAsYHQ/s0/get-started.png" style="display: block; padding: 1em 0; text-align: center; "><img style="width:100%" alt="An illustration titled Get started today. firebase@beta. Followed by a code terminal with the code sample below." border="0" data-original-height="1280" data-original-width="2048" src="https://1.bp.blogspot.com/-j0BPRRXIP14/YP74x5VG_oI/AAAAAAAAFuM/ILPM0YF4TsIjodgiDKE3Ua5CXrjSjCsSACLcBGAsYHQ/s0/get-started.png"/></a></div>
<p>
To learn more about the new library, see our talk at Google I/O. Also check out <a href="https://firebase.google.com/docs/web/modular-upgrade">our upgrade guide</a> for in-depth information about the upgrade process.
</p>
<center><iframe width="560" height="315" src="https://www.youtube.com/embed/r5eJQ3nPc6A" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></center>Firebasehttp://www.blogger.com/profile/14824009575640850018noreply@blogger.com