21 Nov 2017

feedAndroid Developers Blog

Moving Past GoogleApiClient

Posted by Sam Stern, Developer Programs Engineer

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.

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.

The Past: Using GoogleApiClient

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:

The Future: Using GoogleApi

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.

Authenticating with GoogleSignInClient

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:

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 Authenticated API Calls

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.

In general, the new GoogleApi-based APIs have the following benefits:

These new APIs will improve your development process and enable you to make better apps.

Next Steps

Ready to get started with the new Google Play services SDK?

Happy building!

21 Nov 2017 7:36pm GMT

20 Nov 2017

feedAndroid Developers Blog

Google Play Referrer API: Track and measure your app installs easily and securely

Posted by Neto Marin, Developer Advocate

Understanding how people find your app and what they do once they've installed it is crucial to helping you make the right product and marketing decisions. This is especially important when you're deciding your advertising strategy and budget. Today many app measurement companies and ad networks offer ad attribution solutions based on referral data. As such accurate install referral data is vital for correctly attributing app installs, as well as discounting fraudulent attempts for install credit.

To help you obtain more accurate and reliable data about your installs, we're introducing the Google Play Install Referrer API, a reliable way to securely retrieve install referral content. Using this API, your app will get precise information straight from the Play Store, including:

We've tested the API with our App Attribution Program partners including Adjust, AppsFlyer, Singular and TUNE.

"The new Play API provides us with the data we need to effectively detect and prevent click injection; it's a monumental step in securing a crucial information exchange on Android."

- Paul Müller, CTO & Co-Founder, Adjust

"The new Google Play API introduces fresh insights into both mobile ad fraud and the mobile user journey, two key domains with impact across the ecosystem."

- Elad Mashiach, VP, AppsFlyer

"This additional data directly from the Play Store provides increased precision for the Kochava fraud suite to further minimize fraud for our customers."

- Charles Manning, CEO, Kochava

"Google's new API is a game changer that will help marketing analytics platforms like Singular identify and prevent a significant portion of Ad Fraud, and provide security and accuracy to mobile advertisers"

- Gadi Eliashiv, CEO & Co-Founder, Singular

"This new data from Google Play is essential for marketers who demand accountability out of their mobile app install advertising spend. At TUNE, this data is allowing us to outright eliminate entire forms of mobile app install fraud while providing new insight into how mobile app installs are driven."

- Dan Koch, Chief Technical Officer, TUNE


Starting today, the API works with the Play Store app from version 8.3.73 and later for all developers.

Play Install Referrer Library 1.0 now available

To make it easy to integrate the Install Referrer API, we've released the Install Referrer Library 1.0 for Android. The library is available in our Maven repository. To start using it, add the following dependency to your app module build.gradle file:

dependencies {
          ...
          compile 'com.android.installreferrer:installreferrer:1.0'
      }

All communication with the Play Store app happens through a Service, so the first step is to establish the connection between your app and the Play Store. Also, to receive the connection result and updates it's necessary to implement a listener, InstallReferrerStateListener. This listener could be your current Activity or any other class you want to use:

public class MainActivity extends AppCompatActivity 
    implements InstallReferrerStateListener {
    …
}

Now that you have an InstallReferrerStateListener, you can start binding your app to the Play Store app service. To establish the connection, you must build an InstallReferrerClient instance and call the startConnection() method:

InstallReferrerClient mReferrerClient
...
mReferrerClient = newBuilder(this).build();
mReferrerClient.startConnection(this);

Then, handle the connection result in the onInstallReferrerSetupFinished() method. If the connection is OK, the app can retrieve install referrer information, by calling the getInstallReferrer() method:

@Override
public void onInstallReferrerSetupFinished(int responseCode) {
   switch (responseCode) {
       case InstallReferrerResponse.OK:
           try {
               Log.v(TAG, "InstallReferrer conneceted");
               ReferrerDetails response = mReferrerClient.getInstallReferrer();
               handleReferrer(response);
               mReferrerClient.endConnection();
           } catch (RemoteException e) {
               e.printStackTrace();
           }
           break;
       case InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
           Log.w(TAG, "InstallReferrer not supported");
           break;
       case InstallReferrerResponse.SERVICE_UNAVAILABLE:
           Log.w(TAG, "Unable to connect to the service");
           break;
       default:
           Log.w(TAG, "responseCode not found.");
   }
}

For more details about the new API and the client library, visit the Install Referrer Client Library page and the reference documentation.

Other Implementations

If you are not able to use our client library, you can use the AIDL interface and establish the connection with Google Play Store on your own. Check out the IGetInstallReferrerService AIDL reference for details of the methods and the service specification.

What's next?

Check out the Play Install Referrer API documentation for details about the new API, the library's reference docs, and our Quick Start guide.


20 Nov 2017 9:49pm GMT

17 Nov 2017

feedAndroid Developers Blog

Android Things Contest Winners

Posted by Dave Smith, Developer Advocate for IoT

Back in September, we worked with Hackster.io to encourage the developer community to build smart connected devices using Android Things and post their projects to the Developer Challenge for Android Things. The goal was to showcase the combination of turnkey hardware and a powerful SDK for building and maintaining devices at scale.

Thank you to everyone who participated in the contest and submitted a project or idea. We had over 1100 participants register for the contest, resulting in over 350 submissions. Out of that group, we've chosen three winners. Each winner will receive support and tools from Dragon Innovation to develop their concepts into commercial products. Join us in congratulating the following makers!

Best Enterprise Project: Distributed Air Quality Monitoring

Maker: James Puderer

Monitor air quality on a street-by-street level using Android Things, Google Cloud IoT Core, and taxis!

This project showcases how Android Things makes it easy to build devices that integrate with the various services provided by the Google Cloud Platform for robust data collection and analysis. It's a clever end-to-end solution that shows understanding of both the problem domain as well as the technology.


Best Start Up Project: BrewCentral

Maker: Trent Shumay and Steven Pridie

Brewing amazing beer is a balance of art, science, and ritual. The BrewCentral system makes it possible for anyone to do an all-grain brew!

BrewCentral pairs a real-time PID controller with the touch-enabled UI and decision-making compute power of Android Things. The result is a system that accurately controls the time, temperature, and flow rates necessary to achieve repeatable results during a brew cycle. The planned enhancements for cloud-based brewing recipes will make this a connected experience for the entire brewing community.


Best IoT Project: BrailleBox - Braille News Reader

Maker: Joe Birch

BrailleBox is a small piece of hardware that empowers users who are hard-of-sight to read the latest news articles in Braille.

This project is a great use case of using IoT to have a social impact. The current proof of concept streams articles from a news feed to the Braille pad, but this project has the potential to leverage machine learning on the device to translate additional input from the physical world into a Braille result.


Honorable Mentions

The community submitted some amazing projects for the contest, which made the choice of picking only three winners extremely difficult. Here are a few of our favorite projects that weren't selected for a prize:

We encourage everyone to check out all the new projects in the Google Hackster community, and submit your own as well! You can also join Google's IoT Developers Community on Google+, a great resource to get updates, ask questions, and discuss ideas. We look forward to seeing what exciting projects you build!

17 Nov 2017 6:00pm GMT