Posted by Doug Stevenson, Developer Advocate
Starting today, the Android SDKs for Google Play services and Firebase will be using a new build and versioning scheme. This may require some changes to the way you build your Android app, so be sure to read here thoroughly to get all the details.
Here's a quick summary of what's new in these SDKs:
Beginning with version 15 of all Play services and Firebase libraries, version numbers adhere to the semantic versioning scheme. As you know, semver is an industry standard for versioning software components, so you can expect that version number changes for each library indicate the amount of change in the library.
Each Maven dependency matching com.google.android.gms:play-services-* and com.google.firebase:firebase-* is no longer required to have the same version number in order to work correctly at build time and at run time. You will be able to upgrade each dependency independently from each other. As such, a common pattern for specifying the shared version number for Play and Firebase dependencies in Gradle builds will no longer work as expected. The pattern (now anti-pattern) looks like this:
com.google.android.gms:play-services-*
com.google.firebase:firebase-*
buildscript { ext { play_version = '15.0.0' } } dependencies { // DON'T DO THIS!! // The following use of the above buildscript property is no longer valid. implementation "com.google.android.gms:play-services-auth:${play_version}" implementation "com.google.firebase:firebase-auth:${play_version}" implementation "com.google.firebase:firebase-firestore:${play_version}" }
The above Gradle configuration defines a buildscript property called play_version with the version of the Play and Firebase SDKs, and uses that to declare dependencies. This pattern has been helpful to keep all the dependency versions together, as previously required. However, this pattern no longer applies starting with version 15 for each library. Each dependency that you use may now be at different versions. You can expect that individual library updates may not be released at the same time - they may be updated independently.
play_version
In order to support this change in versioning, the Play services Gradle plugin has been updated. If you're using this plugin, it appears like this at the bottom of build.gradle in your app module:
build.gradle
apply plugin: 'com.google.gms.google-services'
Here is what has changed in this plugin:
failOnVersionConflict()
The first version of this plugin that works with the new versioning system is 3.3.0. When working with the new versions of Play and Firebase libraries, it should be added to your buildscript classpath dependencies as follows:
classpath 'com.google.gms:google-services:3.3.0'
If you're not using this plugin, but you still want strict version checking of your dependencies, you can apply this new Gradle plugin instead:
apply plugin: 'com.google.android.gms.strict-version-matcher-plugin'
In order to use this plugin, you will also need to add the following to your buildscript classpath, obtained from Google's Maven Repository:
classpath 'com.google.android.gms:strict-version-matcher-plugin:1.0.0'
If you're not using Android Studio 3.1 to develop your app, you will need to upgrade in order to get the correct version checking behavior within the IDE. Get the newest version of Android Studio here.
With these changes in place, you are now able to adopt new versions of the various SDKs more freely, without a strict requirement to update everything at once. It also enables the development teams for each SDK to ship fixes and enhancements more quickly. Going forward, you can track the releases for Play services SDKs and Firebase SDKs with the provided links.
The release of version 11.6.0 of the Google Play services SDK moves a number of popular APIs to a new paradigm for accessing Google APIs on Android. We have reworked the APIs to reduce boilerplate, improve UX, and simplify authentication and authorization.
The primary change in this release is the introduction of new Task and GoogleApi based APIs to replace the GoogleApiClient access pattern.
Task
GoogleApi
GoogleApiClient
The following APIs are newly updated to eliminate the use of GoogleApiClient:
These APIs join others that made the switch in previous releases, such as the Awareness, Cast, Places, Location, and Wallet APIs.
Here is a simple Activity that demonstrates how one would access the Google Drive API using GoogleApiClient using a previous version of the Play services SDK:
public class MyActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { private static final int RC_SIGN_IN = 9001; private GoogleApiClient mGoogleApiClient; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); GoogleSignInOptions options = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(Drive.SCOPE_FILE) .build(); mGoogleApiClient = new GoogleApiClient.Builder(this) .enableAutoManage(this, this) .addConnectionCallbacks(this) .addApi(Auth.GOOGLE_SIGN_IN_API, options) .addApi(Drive.API) .build(); } // ... // Not shown: code to handle sign in flow // ... @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { // GoogleApiClient connection failed, most API calls will not work... } @Override public void onConnected(@Nullable Bundle bundle) { // GoogleApiClient is connected, API calls should succeed... } @Override public void onConnectionSuspended(int i) { // ... } private void createDriveFile() { // If this method is called before "onConnected" then the app will crash, // so the developer has to manage multiple callbacks to make this simple // Drive API call. Drive.DriveApi.newDriveContents(mGoogleApiClient) .setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() { // ... }); } }
The code is dominated by the concept of a connection, despite using the simplified "automanage" feature. A GoogleApiClient is only connected when all APIs are available and the user has signed in (when APIs require it).
This model has a number of pitfalls:
onConnected
Over the years the need to replace GoogleApiClient became apparent, so we set out to completely abstract the "connection" process and make it easier to access individual Google APIs without boilerplate.
Rather than tacking multiple APIs onto a single API client, each API now has a purpose-built client object class that extends GoogleApi. Unlike with GoogleApiClient there is no performance cost to creating many client objects. Each of these client objects abstracts the connection logic, connections are automatically managed by the SDK in a way that maximizes both speed and efficiency.
When using GoogleApiClient, authentication was part of the "connection" flow. Now that you no longer need to manage connections, you should use the new GoogleSignInClient class to initiate authentication:
GoogleSignInClient
public class MyNewActivity extends AppCompatActivity { private static final int RC_SIGN_IN = 9001; private GoogleSignInClient mSignInClient; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); GoogleSignInOptions options = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(Drive.SCOPE_FILE) .build(); mSignInClient = GoogleSignIn.getClient(this, options); } private void signIn() { // Launches the sign in flow, the result is returned in onActivityResult Intent intent = mSignInClient.getSignInIntent(); startActivityForResult(intent, RC_SIGN_IN); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RC_SIGN_IN) { Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); if (task.isSuccessful()) { // Sign in succeeded, proceed with account GoogleSignInAccount acct = task.getResult(); } else { // Sign in failed, handle failure and update UI // ... } } } }
Making API calls to authenticated APIs is now much simpler and does not require waiting for multiple callbacks.
private void createDriveFile() { // Get currently signed in account (or null) GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this); // Synchronously check for necessary permissions if (!GoogleSignIn.hasPermissions(account, Drive.SCOPE_FILE)) { // Note: this launches a sign-in flow, however the code to detect // the result of the sign-in flow and retry the API call is not // shown here. GoogleSignIn.requestPermissions(this, RC_DRIVE_PERMS, account, Drive.SCOPE_FILE); return; } DriveResourceClient client = Drive.getDriveResourceClient(this, account); client.createContents() .addOnCompleteListener(new OnCompleteListener<DriveContents>() { @Override public void onComplete(@NonNull Task<DriveContents> task) { // ... } }); }
Before making the API call we add an inline check to make sure that we have signed in and that the sign in process granted the scopes we require.
The call to createContents() is simple, but it's actually taking care of a lot of complex behavior. If the connection to Play services has not yet been established, the call is queued until there is a connection. This is in contrast to the old behavior where calls would fail or crash if made before connecting.
createContents()
In general, the new GoogleApi-based APIs have the following benefits:
GoogleSignInAccount
PendingResult
These new APIs will improve your development process and enable you to make better apps.
Ready to get started with the new Google Play services SDK?
Happy building!
The 11.0.0 release of the Google Play services SDK includes a new way to access LocationServices. The new APIs do not require your app to manually manage a connection to Google Play services through a GoogleApiClient. This reduces boilerplate and common pitfalls in your app.
Read more below, or head straight to the updated location samples on GitHub.
The LocationServices APIs allow you to access device location, set up geofences, prompt the user to enable location on the device and more. In order to access these services, the app must connect to Google Play services, which can involve error-prone connection logic. For example, can you spot the crash in the app below?
Note: we'll assume our app has the ACCESS_FINE_LOCATION permission, which is required to get the user's exact location using the LocationServices APIs.
ACCESS_FINE_LOCATION
public class MainActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); GoogleApiClient client = new GoogleApiClient.Builder(this) .enableAutoManage(this, this) .addApi(LocationServices.API) .build(); client.connect(); PendingResult result = LocationServices.FusedLocationApi.requestLocationUpdates( client, LocationRequest.create(), pendingIntent); result.setResultCallback(new ResultCallback() { @Override public void onResult(@NonNull Status status) { Log.d(TAG, "Result: " + status.getStatusMessage()); } }); } // ... }
If you pointed to the requestLocationUpdates() call, you're right! That call throws an IllegalStateException, since the GoogleApiClient is has not yet connected. The call to connect() is asynchronous.
requestLocationUpdates()
IllegalStateException
connect()
While the code above looks like it should work, it's missing a ConnectionCallbacks argument to the GoogleApiClient builder. The call to request location updates should only be made after the onConnected callback has fired:
public class MainActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { private GoogleApiClient client; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); client = new GoogleApiClient.Builder(this) .enableAutoManage(this, this) .addApi(LocationServices.API) .addConnectionCallbacks(this) .build(); client.connect(); } @Override public void onConnected(@Nullable Bundle bundle) { PendingResult result = LocationServices.FusedLocationApi.requestLocationUpdates( client, LocationRequest.create(), pendingIntent); result.setResultCallback(new ResultCallback() { @Override public void onResult(@NonNull Status status) { Log.d(TAG, "Result: " + status.getStatusMessage()); } }); } // ... }
Now the code works, but it's not ideal for a few reasons:
onCreate
The new LocationServices APIs are much simpler and will make your code less error prone. The connection logic is handled automatically, and you only need to attach a single completion listener:
LocationServices
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(this); client.requestLocationUpdates(LocationRequest.create(), pendingIntent) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { Log.d("MainActivity", "Result: " + task.getResult()); } }); } }
The new API immediately improves the code in a few ways:
The new API will automatically resolve certain connection failures for you, so you don't need to write code that for things like prompting the user to update Google Play services. Rather than exposing connection failures globally in the onConnectionFailed method, connection problems will fail the Task with an ApiException:
client.requestLocationUpdates(LocationRequest.create(), pendingIntent) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { if (e instanceof ApiException) { Log.w(TAG, ((ApiException) e).getStatusMessage()); } else { Log.w(TAG, e.getMessage()); } } });
Try the new LocationServices APIs out for yourself in your own app or head over to the android-play-location samples on GitHub and see more examples of how the new clients reduce boilerplate and simplify logic.
Posted by Jason Douglas, PM Director for Actions on Google
The Google Assistant brings together all of the technology and smarts we've been building for years, from the Knowledge Graph to Natural Language Processing. To be a truly successful Assistant, it should be able to connect users across the apps and services in their lives. This makes enabling an ecosystem where developers can bring diverse and unique services to users through the Google Assistant really important.
In October, we previewed Actions on Google, the developer platform for the Google Assistant. Actions on Google further enhances the Assistant user experience by enabling you to bring your services to the Assistant. Starting today, you can build Conversation Actions for Google Home and request to become an early access partner for upcoming platform features.
Conversation Actions for Google Home
Conversation Actions let you engage your users to deliver information, services, and assistance. And the best part? It really is a conversation -- users won't need to enable a skill or install an app, they can just ask to talk to your action. For now, we've provided two developer samples of what's possible, just say "Ok Google, talk to Number Genie " or try "Ok Google, talk to Eliza' for the classic 1960s AI exercise.
You can get started today by visiting the Actions on Google website for developers. To help create a smooth, straightforward development experience, we worked with a number of development partners, including conversational interaction development tools API.AI and Gupshup, analytics tools DashBot and VoiceLabs and consulting companies such as Assist, Notify.IO, Witlingo and Spoken Layer. We also created a collection of samples and voice user interface (VUI) resources or you can check out the integrations from our early access partners as they roll out over the coming weeks.
Coming soon: Actions for Pixel and Allo + Support for Purchases and Bookings
Today is just the start, and we're excited to see what you build for the Google Assistant. We'll continue to add more platform capabilities over time, including the ability to make your integrations available across the various Assistant surfaces like Pixel phones and Google Allo. We'll also enable support for purchases and bookings as well as deeper Assistant integrations across verticals. Developers who are interested in creating actions using these upcoming features should register for our early access partner program and help shape the future of the platform.
Posted by Isabella Chen, Software Engineer, and Laurence Moroney, Developer Advocate
Starting with Google Play services 8.3, we did a major revamp of the Google Sign-In APIs, supporting both client and server auth. Behind the scenes, these APIs use OAuth 2.0 tokens to ensure secure authentication and authorization. To maintain security, we provide tools in the Google Developers Console to register the clients using these tokens.
In this post, we’ll discuss the important task of registering OAuth clients for Google Sign-In, and the tools that we offer to make this as easy as possible.
Here are some scenarios that might apply to you:
In this post, we’ll cover some details on this process and address common pitfalls.
If you have not used Google Sign-In before, you can start integrating the API into your app by following the ‘Get a configuration file’ steps on this site. You’ll be taken to a setup wizard that will create an OAuth 2.0 client ID as shown in Figure 1.
Once you’ve specified your app, you’ll be taken to a screen to choose and configure services such as Google Sign-In, Cloud Messaging or Google Analytics that you want your app to be able to use.
Choose Google Sign-In. In order to use it, you’ll need to get the SHA-1 of the signing certificate for your Android app. This can either be a debug or a release certificate, and for the purposes of this blog you’ll look at a debug one, but keep in mind that you’ll need to repeat this process for each package / certificate pair you end up using (described in the last section below).
You can get the debug SHA-1 using the keytool command like this:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
Once you have your SHA-1, enter it as seen in Figure 2.
Now that your project is set up, you can get started with integrating the Sign-In API. But if you need to configure your project to work with a backend server or additional package name / keystores, keep reading the sections below.
If you have your own web or cloud server with data for your application, you’ll need OAuth credentials for your backend. Details on doing this can be found in the ID token and server auth code documentation.
Before using these flows, you’ll need to make sure you register your web server correctly in the Google Developers Console. Once there, you’ll be asked to select your project. See Figure 3.
Once you’ve selected your project, press the ‘Continue’ button, and you’ll go directly to the Credentials tab where all credential types are managed. Check the “OAuth 2.0 client IDs” section, and you will see the “Web client” and “Android client for com.my.package.name” that were created for you by the setup wizard. See Figure 4.
Take note of the Client ID for for your Web client, you’ll need it for both your app and server as illustrated below. (If you’ve created your project in the past and there’s no OAuth 2.0 client ID with Type “Web application”, then you will need to create one by selecting ‘New Credentials’ -> ‘OAuth client ID’.)
If you use an ID token flow for backend authentication, when you start developing your Android app, request an ID token in your GoogleSignInOptions, supplying the web client ID for your server:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(serverClientId) .requestEmail() .build();
And then on your server, set the same OAuth client ID for your web application to be the audience:
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory) .setAudience(Arrays.asList(serverClientId)) .setIssuer("https://accounts.google.com") .build();
Successful verification will allow you to authenticate and issue a session for this newly signed-in user.
Alternatively, if you are using the server auth code flow for backend access to Google APIs, request a server auth code in your GoogleSignInOptions on Android, again supplying the web client ID for your server:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(new Scope(Scopes.DRIVE_APPFOLDER)) .requestServerAuthCode(serverClientId) .requestEmail() .build();
And then on the server, both the OAuth client ID and the “Client secret” will be useful. The server SDK from Google can directly consume a downloaded JSON configuration file. You can click the download icon to download the JSON file (as shown in Figure 4) and use below code to construct GoogleClientSecrets:
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load( JacksonFactory.getDefaultInstance(), new FileReader(PATH_TO_CLIENT_SECRET_FILE));
At which point you can access authenticated Google APIs on behalf of the signed-in user. Note that the “client secret” is really a secret that you should never reveal in your Android client.
Note that it can be common for apps to have different package names as well as different certificates (and thus SHA-1 keys) for various types of environment (such for different developers or test and release environments). Google uses your package name together with SHA-1 signing-certificate fingerprint to uniquely identify your Android application. It’s important to register every package name + SHA1 fingerprint pair in Google Developers Console.
For example, to register the release version of this package, you can do so by selecting ‘New Credentials’ -> ‘OAuth client ID’, shown in Figure 5 below, and then following the steps to add the package name and production keystore SHA-1.
Now you are ready to handle the different environments where your app might be running and release to your users!
Hopefully, this has been helpful to you in understanding how to register for OAuth keys to keep your apps and servers secure. For more information, check out the Google Developers homepage for Identity.
Posted by Atul Kumar, Google Play Policy
More than 1 billion Android users come to Google Play every month to discover their favorite apps and games, enabling developers to reach a vast global audience and build successful businesses on the platform. To maintain a positive experience for both users and developers, the Google Play Developer Program Policies play a central role in helping make Google Play an open, safe and enjoyable ecosystem by educating the community and defining appropriate content and activities in the store.
We constantly listen to our developers and users to maintain fair and defined policies and look for ways to improve how we communicate those policies to help developers avoid accidental pitfalls. As part of that effort, we’ve redesigned our Developer Program Policy Center to communicate our policies with greater transparency and clarity. This redesign includes:
From making it easier to self-correct minor violations in minutes using the app publishing status feature to improving our policy communication, the new policy center is part of our ongoing effort to improve the developer experience. We invite you to explore the new policy center and and share your feedback.
Posted by Fergus Hurley, Product Manager, Google Play
Millions of users rate and review your apps every day on Google Play. From feature requests to technical issues, ratings and reviews offer a wealth of information about what people like and dislike. Since 2013, you’ve been able to reply to reviews on Google Play, giving you a direct communication channel with your most engaged users. You've told us you value having this channel because it helps you iterate on user feedback faster on Android than other platforms. In the last few months, we’ve made a number of improvements in the Google Play Developer Console to help you better analyze and manage ratings and reviews so that you can improve your app experience and boost its rating.
Improvements to ratings and reviews
We recently revamped ratings and reviews with features you can now find on dedicated pages in the Developer Console:
Learn from other developers on how to make the most of ratings and reviews
Photo Editor by Aviary is a photo editing app with a strong focus on simplicity and intuitive use. Ratings and reviews and other Android features allow Aviary to iterate on builds two to three times faster compared to other platforms while being in a regular dialogue with their users.
Glu Mobile is a mobile gaming company known for Racing Rivals, Cooking Dash 2016 and its upcoming Taylor Swift game. Ratings and reviews features help Glu engage their audience, gather feedback, and manage user satisfaction. “Google’s review highlights allow us to see a snapshot of game features users like or dislike at a glance. We monitor review trends, watch out for notifications, and respond to reviews for our games,” says Niccolo de Masi, Glu Mobile CEO. Here are some tips Glu is using to master ratings and reviews in the Developer Console:
We hope these tools help you better engage with your audience and improve your app. Visit the Developer Console Help Center to find out more about seeing and managing ratings and reviews. For more tools and best practices to help you grow a successful business, download The Secrets to App Success on Google Play.
Posted Steven Soneff, Product Manager, Google Identity
More than 30 percent of users signing in to the Netflix app on Android no longer have to enter a password thanks to Google’s Smart Lock for Passwords. Learn more
It’s been six months since the launch of Smart Lock for Passwords and we are thrilled with the impact it has made in getting users signed back in to many of their favorite apps. Million of users have been seamlessly signed in using saved accounts for over 40 major apps when going from one Android device to another or from Chrome to Android and vice versa. This first wave of developers have realized that removing the friction of sign-in increases user re-engagement, monetization opportunities, and cross-device analytics, improving the value and experience of their users.
The New York Times has seen 80 percent of their new sign-in events assisted by Smart Lock. Meanwhile, the Netflix customer support team found over a 20 percent reduction in support cases related to account recovery for their Android user base. Users strongly choose to stay signed in across their devices with over 60 percent opt-in to save sign-in info for major Smart Lock-enabled apps. And many of these developers were able to realize these gains with less than a day’s work by making only client-side changes to their app. To learn more about Smart Lock for Passwords, visit our developer site.
With the latest release of Google Play services, we’ve made some enhancements to the Smart Lock for Passwords API to help you sign up new users or sign existing users in more quickly. Using the new method to retreive sign-in "hints", your users will see a dialog with a list of email addresses that they can select in a single tap:
This new experience is particularly important with Android Marshmallow’s runtime permissions model. To simplify and improve the user experience, this dialog doesn’t require device permissions and includes any email addresses that the user has saved with Smart Lock, not just the accounts on the device. This means that you can improve your sign-in and sign-up flows so that most of your users never need to type their email address. Apps using this dialog have seen nearly three-quarters of users select an entry shown, improving sign-up rates.
Next, after the user has tapped and shared their email address, with some server-side support, a sophisticated app can fully tailor the sign-in flow. By using the email address, you can check your database to see if a user has already registered for an account. You can then intelligently render either the sign-in or sign-up screens with the user’s email address, name and profile photo pre-filled.
It’s possible to do even better: if the user chooses a Google account from the dialog, an OpenID Connect ID Token is provided. This can save your app from having to verify email addresses for new accounts or skip the password altogether for returning users. ID tokens are also used by Google Sign-In to authenticate in place of a password, and are a strong assertion from Google that the owner of the given email address is present. If users on your site recover their passwords by email, then an ID token from Google is giving you the same assertion that the user owns the email address and is signed in to this device with that email address. You can also consider presence of ID token in addition to the password a signal to prevent password cracking and abuse.
We’ve found that the majority of users on Android use the email address that’s signed in on their device as their account for third-party apps, so this means seamlessly signing in most of your returning users, or creating a new account with one tap!
Here’s a recap of how to streamline your app’s sign-in flow:
When your app starts, request stored Smart Lock credentials, and go straight to the user’s content when possible. Create a request for password or Google credentials, then listen for a callback with the results. Sign in immediately if stored user credentials (username / password, ID token, etc.) is available.
CredentialRequest request = new CredentialRequest.Builder() .setSupportsPasswordLogin(true) .setAccountTypes(IdentityProviders.GOOGLE) // you can add other identity providers, too .build(); Auth.CredentialsApi.request(mCredentialsApiClient, request).setResultCallback( new ResultCallback<CredentialRequestResult>() { public void onResult(CredentialRequestResult result) { if (result.getStatus().isSuccess()) { handleCredential(result.getCredential()) // sign in automatically!
When the user wants or needs to sign in with their email address, show the picker to help them input it. Create a request for hints, pass control to the system to display UI, and handle the result when the user selects an entry.
HintRequest hintRequest = new HintRequest.Builder() .setEmailAddressIdentifierSupported(true) .setAccountTypes(IdentityProviders.GOOGLE) .build(); PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(mCredentialsApiClient, hintRequest); startIntentSenderForResult(intent.getIntentSender(), RC_HINT, null, 0, 0, 0); ... onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case RC_HINT: if (resultCode == RESULT_OK) { Credential hint = data.getParcelableExtra(Credential.EXTRA_KEY); handleCredential(hint);
The result from the hint request will contain the user’s selected identifier and an ID token if it is a Google account on the device. If you use the ID token, you must send and verify it on your server for security. Note that this token will also include a claim if the email address is verified, so you can skip any email verification step. If no token is present, or you can’t do server-side validation, just pre-fill the email field for the user.
handleCredential(Credential credential) { if (!credential.getIdTokens().isEmpty()) { credential.getIdTokens().get(0).getIdToken(); // send the ID token string to your server } else { // otherwise, try fill the sign-in form fields and submit if password is available mEmailField.setText(credential.getId()); mPasswordField.setText(credential.getPassword());
On your server, after validating the ID token, use it to create an account or sign the user in without need for their password. Google provides libraries to do token validation, or you can use an open-source implementation. The ID token contains the user’s email address, and you can look it up in your database to determine whether an account needs to be created.
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory) .setIssuer("https://accounts.google.com") .setAudience(Arrays.asList(String.format("android://%s@%s", SHA512_HASH, PACKAGE_NAME))) .build(); ... GoogleIdToken idToken = verifier.verify(idTokenString); if (idToken == null) { Log.w(TAG, "ID Token Verification Failed, check the README for instructions."); return; } GoogleIdToken.Payload payload = idToken.getPayload(); Log.d(TAG, "IdToken:Email:" + payload.getEmail()); Log.d(TAG, "IdToken:EmailVerified:" + payload.getEmailVerified()); // based on the email address, determine whether you need to create account // or just sign user in
Then save the user’s email address credential “hint” in Smart Lock for automatic sign-in next time. Simply call the Credentials API save method with the hint and either set the user-entered password, or set the account type if you logged the user in with an ID token.
Credential credential = new Credential.Builder(hint) // if you signed in with ID token, // set account type to the URL for your app (instead of a password field) //.setAccountType("https://yourdomain.com") .setPassword(password) .build(); Auth.CredentialsApi.save(mCredentialsApiClient, credential).setResultCallback( new ResolvingResultCallbacks<Status>(this, RC_SAVE) {
To learn more about the basics of a Smart Lock API integration, check out our code lab for a step-by-step guide. We’re excited to make authentication without passwords possible via Smart Lock and are looking forward to a world where not only credentials can be managed more effectively, but apps can get their users signed in and up quickly and securely without the friction of typing usernames and passwords. We’d love to hear your feedback or questions!
Posted by Lily Sheringham, Google Play team
Founded in 2010, SGN is a Los Angeles based mobile game developer with hit titles including Cookie Jam, Panda Pop, Juice Jam and Book of Life: Sugar Smash. They now have more than 200 employees and are one of the fastest growing cross-platform gaming developers.
SGN used Store Listing experiments to test multiple variants across their portfolio of games. For Cookie Jam, they saw an 8 percent increase in conversions simply by changing the background color of their app icon. They also saw increased installs following tests with the Panda Pop app icon and by changing the character in their Book of Life: Sugar Smash app icon.
Watch Josh Yguado, Co-founder and President of SGN, and Matthew Casertano, SVP of Game Operations, talk about how using Store Listing Experiments helped SGN improve their ROI, conversion rates and gamer retention.
Find out more about how to run tests on your Store Listing to increase installs and achieve success with the new guide to ‘Secrets to App Success on Google Play’.
Gifted Mom is an app developed in Cameroon which provides users with basic, yet critical information about pregnancy, breastfeeding and child vaccinations. The widespread use of Android smartphones in Africa has meant that Gifted Mom has been able to reach more people at scale and improve lives.
Watch the creators of Gifted Mom, developer Alain Nteff and doctor Conrad Tankou, explain how they built their business and launched Gifted Mom on Google Play. They also talk about their plans to grow and help people in other developing countries across the continent in the next three years, in order to ultimately tackle maternal and infant mortality.
Find out more about building apps for Android and how to find success on Google Play.
Posted by Laurence Moroney, Developer Advocate
We’re delighted to announce the availability of Google Play services 8.3. There’s a lot of new information to share with you about what’s available to you in this release.
A big part of this release is focused on user identity. We’ve revamped the Sign In with Google APIs to make implementation simpler and provide users a streamlined experience. First off, the new Google Sign-In no longer requires the device accounts permissions, a big win when you start to develop for Marshmallow. The API also supports the latest Google branding. When using Google Play services 8.3, you’ll find a SignInButton that looks like this with the default scopes:
Previously, users would have to touch a sign in button, and then follow several steps (i.e. selecting account, giving permission to access profile information, and possibly needing to create a Google+ account). With Google Play services 8.3, only one tap is needed for basic profile access.
You can check out the documentation for the new API here.
And to make signing in easier across devices, whether you use Google Sign-In or still have password-based authentication, the Smart Lock APIs received some important updates. We’ve added a new API method to show a dialog that helps your user select a previously-used email address to pre-fill sign in or up forms easily: check out getHintPicker (sample code). This doesn’t require any device permissions and provides an alternative to a picker you may have previously populated from accounts on the device, which would now require a runtime permission with Marshmallow.
getHintPicker
You can use this hint information to populate an entire sign-up form with name, email address, and profile picture with one tap, or even direct the user into a sign-in or sign-up flow intelligently based on their email address. Better yet, if the entry the user picked matches an account on the device, Google can provide a verified email address in the hint, which you can use to skip email verification and authenticate the user if your system can support ID tokens, similar to Google Sign-In.
For determining location, Google Play services provides a Fused Location Provider (FLP) which abstracts the underlying location sensors, such as GPS, WiFi, and the cell radio signal, into a single easy-to-use API. We’ve made some improvements to the FLP when it comes to batching. Prior to version 8.3, the batch location APIs would allow the FLP to save power by consolidating network traffic, but when an app removed a batching location request, the batch would be cleared. You may not want this behavior, so we’ve added an API that can return any batched locations immediately. Check the flushLocations and removeLocationUpdates method calls on the FusedLocationProviderApi for more details.
flushLocations
removeLocationUpdates
FusedLocationProviderApi
App Invites is a technology that enables your users to share your app with people they know. If you build using App Invites, Google Play services 8.3 has an update that will make coding much simpler. Now, you can use the AppInvite.AppInviteApi.getInvitation() method. This will set up a ResultCallback that you can use to launch your deep link activity, drastically simplifying your code.
AppInvite.AppInviteApi.getInvitation()
The Play game services Player Stats API also gets an update. The latest version now includes a new signal for the probability that a player is about to churn. Developers can use this signal to offer special promotions to improve retention. For example, a developer could provide a discount on a power-up for players that are at risk of churning.
Finally, if you are developing for wearables, you’ll know that battery life and optimization of power usage are critical in having a great user experience. With Google Play services 8.3, we’ve updated the DataApi to allow for urgency in how data items are synced. Now, a priority can be added to the data item to determine when it should be synced. For example, if you are building an app that requires immediate syncing, such as a remote control app, it can still be done immediately by calling setUrgent(), but for something such as updating your contacts, you could tolerate some delay. Non-urgent DataItems may be delayed for up to 30 minutes, but you can expect that in most cases they will be delivered within a few minutes. Low priority is now the default, so setUrgent() is needed to obtain the previous timing.
Filter support has been added to listeners in the Android Wear API, allowing listeners to only receive a subset of changes on both phones and watches. Listeners registered in the Android manifest should be filtered to only receive events that require launching the process, with the remaining events being delivered to live listeners added via methods such as addListener(). This reduces the need for listeners to filter out uninteresting events, making applications and the system more efficient.
That’s it for this release of Google Play services. To learn more, visit the Google Developers site.
Posted by, Ian Lake, Developer Advocate
One of the benefits of Android development is the flexibility provided by the large number of APIs in the Android framework and Support Library, not even including the Google Play services APIs. However, that can be a lot to understand, particularly when confronted with multiple options or design decisions. Thankfully, things are about to get a lot clearer with a new series: Android Development Patterns.
The goal of Android Development Patterns is to focus on the fundamental components and best practices that can make the biggest difference in your app. We spend time talking about the why behind each API, so that you know exactly what is best for your situation.
Centered on Android framework APIs, the Android Support Library, and high level app structure and design, we’ll augment the many videos on the Android Developers YouTube channel to bring the focus back towards Android development at its core.
Android Development Patterns are more than just videos. You’ll find written pro-tips from in-house experts at Google, such as Joanna Smith and Ian Lake, every week through the Android Development Patterns Google+ Collection.
Watch all of Android Development Patterns!
Posted by, Laurence Moroney, Developer Advocate
Along with new platform features, Android 6.0 Marshmallow has a new permissions model that streamlines the app install and auto-update process. Google Play services 8.1 is the first release to support runtime permissions on devices running Android 6.0. and will obtain all the permissions it needs to support its APIs. As a result, your apps won’t normally need to request permissions to use them. However, if you update your apps to target API level 23, they will still need to check and request runtime permissions, as necessary.
To update your Google Play services apps to handle the latest permissions model, it’s good practice to manage the user’s expectations in setting permissions that the runtime may require. Below are some best practices to help you get started.
For the purposes of this post, ensure that your API level and Target SDK are set to at least 23. Additionally, ensure that, for backwards compatibility, you are using the V4 support library to verify and request permissions. If you don’t have it already, add it to your gradle file:
com.android.support:support-v4:23.0.1
You’ll also need to declare Permissions in your AndroidManifest.xml file. There’s no change here. Whatever permissions your app has always needed should be declared in your AndroidManifest.xml file with the uses-permission tag. Here’s an example:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Documentation on maps and location, including a walkthrough on connecting may be found here.
Here’s an example:
@Override public void onConnectionFailed(ConnectionResult result) { if (mResolvingError) { // Already attempting to resolve an error. return; } else if (result.hasResolution()) { try { mResolvingError = true; result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR); } catch (SendIntentException e) { // There was an error with the resolution intent. Try again. mGoogleApiClient.connect(); } } else { // Show dialog using GooglePlayServicesUtil.getErrorDialog() showErrorDialog(result.getErrorCode()); mResolvingError = true; } }
It’s easy to assume that once you can connect, and you’ve declared the required permissions for APIs that you want to use in your AndroidManifest.xml file, that future calls will be fine. However, it is vital to ensure that you have the required permission before calling an API or connecting to the GoogleApiClient. This can be done using the checkSelfPermission method of ActivityCompat, Fragment or ContextCompat.
checkSelfPermission
ActivityCompat
Fragment
ContextCompat
If the call returns false, i.e. the permissions aren’t granted, you’ll use requestPermissions to request them. The response to this will be returned in a callback which you will see in the next step.
requestPermissions
private static final int REQUEST_CODE_LOCATION = 2; if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Request missing location permission. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_LOCATION); } else { // Location permission has been granted, continue as usual. Location myLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); }
In step 2, if the permission wasn’t granted by the user, the requestPermissions method was called to ask the user to grant them. The response from the user is captured in the onRequestPermissionsResult callback. You need to implement this, and always check the return values because the request could be denied or cancelled. Note that you might need to request multiple permissions here -- this sample just checks for a single permission -- you may need to check for more.
onRequestPermissionsResult
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == REQUEST_CODE_LOCATION) { if(grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // success! Location myLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); } else { // Permission was denied or request was cancelled } }
If the user has previously denied the permission request, your app should display an additional explanation before requesting the permission again. Indeed, if the permissions are non trivial for the core features of the app, and the user is confused as to why they are needed, it would be recommended to guide them.
In this case, before the call to requestPermissions (step 2, above), you should call shouldShowRequestPermissionRationale, and if it returns true, you should create some UI to display additional context for the permission.
shouldShowRequestPermissionRationale
As such your code from Step 2 might look like this:
private static final int REQUEST_CODE_LOCATION = 2; if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Check Permissions Now if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { // Display UI and wait for user interaction } else { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_LOCATION); } } else { // permission has been granted, continue as usual Location myLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); }
Note that in this case your user may still deny the permissions, in which case you will need to craft your app so as not to be in a situation where a denied permission affects parts of the app where it shouldn’t. Refer to the best practices section on the Android developer’s site for more details and guidance.
If you’ve built any applications that use Google Play services, I’d recommend that you download the Google Play services 8.1 SDK, and rebuild your applications using it, testing against the most recent versions of Android 6.0, which you can download from the Android Developers site.
Get started with building for Android 6.0
Android Permissions design guidelines
Google IO 2015 Session on Android M Permissions
Samples for Google Play services 8.1 with coding best practices