Hide

Save to Google API for Android Tutorial

The Save to Google API for Android lets users save Wallet Objects to their Google Wallet with the click of a button displayed in your Android app. This tutorial guides you through integrating Save to Google functionality into your Android app.

The API is provided as part of Google Play Services, which provides core functionality for Android apps. For the purposes of this tutorial, we'll assume that you are familiar with the basic concepts and skills of application development for the Android platform. If you need to learn about Android development before getting started, work through some lessons in the Training for Android Developers.

Contents

1. Set up

To get started with this tutorial, create a client ID for your project, download and review the sample source code, and set up Google Play Services.

Obtain credentials and a client ID for your app

To access the Save to Google API for Android, you'll need to obtain a client ID for OAuth 2.0 authorization in the Google Developers Console. The client ID is generated automatically when you register your app. You'll also need the SHA1 fingerprint in your developer's key to generate a client ID.

  1. Go to the Google Developers Console.
  2. Select a project, or create a new one.
  3. In the sidebar on the left, select APIs & auth.
  4. In the sidebar on the left, select Credentials.
  5. To register your certificate, you need to get the certificate's SHA1 fingerprint, by switching to a terminal window and running the the Keytool utility:
    keytool -exportcert -alias androiddebugkey -keystore path_to_debug_or_production_keystore -list -v

    For the debug keystore, the password is android.

    The Keytool prints the fingerprint to the shell. For example:

    $ keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v
    Enter keystore password: Type "android" if using debug.keystore
    Alias name: androiddebugkey
    Creation date: Aug 27, 2012
    Entry type: PrivateKeyEntry
    Certificate chain length: 1
    Certificate[1]:
    Owner: CN=Android Debug, O=Android, C=US
    Issuer: CN=Android Debug, O=Android, C=US
    Serial number: 503bd581
    Valid from: Mon Aug 27 13:16:01 PDT 2012 until: Wed Aug 20 13:16:01 PDT 2042
    Certificate fingerprints:
       MD5:  1B:2B:2D:37:E1:CE:06:8B:A0:F0:73:05:3C:A3:63:DD
       SHA1: D8:AA:43:97:59:EE:C5:95:26:6A:07:EE:1C:37:8E:F4:F0:C8:05:C8
       SHA256: F3:6F:98:51:9A:DF:C3:15:4E:48:4B:0F:91:E3:3C:6A:A0:97:DC:0A:3F:B2:D2:E1:FE:23:57:F5:EB:AC:13:30
       Signature algorithm name: SHA1withRSA
       Version: 3

    Copy the SHA1 fingerprint, which is highlighted in the example above.

  6. Back in the Console, do the following:
    1. Click Create New Client ID.
    2. Select Installed application and Android.
    3. In the Package name field, enter your Android's app's package name.
    4. Paste the SHA1 fingerprint into the Signing certificate fingerprint text box.
    5. Click Create Client ID.

Set up the sample and Google Play Services

Follow these setup instructions to import the Google Play Services library. If you don't already have it, you'll need to get the Android SDK. All other resources for the current sample are provided in Wobs_S2W.zip

2. Add the Save to Google button to your UI

The next step is to add the Save to Google button to your app. Google Wallet provides an Android SDK button for you to integrate into your app. The button assets are available in the wallet_button_save_card_to_google.zip archive.

This archive contains 9-patch drawables in mdpi, hdpi, xhdpi and xxhdpi for the background and foreground states for the button. Also, the archives contain buttons in disabled states.

To incorporate a button in your application, copy over the resources from the archive into the res/ folder of your application and add the following code to your Android layout file. Note that each button requires its unique contentDescription string and minWidth value in addition to the correct value for src.

<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="48dp"
             android:minWidth="200dp"
             android:background="@drawable/wallet_button_background"
             android:contentDescription="@string/wallet_save_card_to_google_wallet"
             android:src="@drawable/wallet_button_save_card_to_foreground" />
  • Note that the contentDescription string resource value must be Save card to Google.
  • The layout_height for the button is 48dp and minWidth must be 200dp.

3. Initialize the Google API client

The GoogleApiClient object wraps a ServiceConnection to Google Play services and is used to communicate with the native Save to Google API. The GoogleApiClient becomes functional after the asynchronous connection has been established with the service, indicating that:

  • Google Play services is running on the device and your Activity successfully bound the service connection
  • the user has selected an account that they wish to use with your app
  • the user's account has granted the permissions that your app is requesting

Typically, you want to manage the GoogleApiClient lifecycle in your activity's lifecycle:

The following code snippet illustrates how an app can instantiate a Google API client for saving a Wallet Object to Google, and then connect:

private GoogleApiClient createGoogleApiClient() {
    return new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(Wallet.API, new Wallet.WalletOptions.Builder()
                    .setEnvironment(WalletConstants.ENVIRONMENT_PRODUCTION)
                    .setTheme(WalletConstants.THEME_HOLO_DARK).build()).build();
                  }

                    ...

protected void onStart(){
  super.onStart();
  googleApiClient.connect();
}

protected void onStop() {
  googleApiClient.disconnect();
  super.onStop();
}

4. Create an object

The next step is to create the object. Following are examples of creating objects using the builder pattern:

Loyalty Object

    // Define Points
    LoyaltyPoints points = LoyaltyPoints.newBuilder()
        .setLabel("Points")
        .setType("points")
        .setBalance(LoyaltyPointsBalance.newBuilder().setString("500").build()).build();

    // Define Text Module Data
    List textModulesData = new ArrayList();
    TextModuleData textModuleData = new TextModuleData("Jane's Baconrista Rewards", "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
    textModulesData.add(textModuleData);

    // Define Links Module Data
    List uris = new ArrayList();
    UriData uri1 = new UriData("http://www.baconrista.com/myaccount?id=1234567890","My Baconrista Account");
    uris.add(uri1);

    List imageUris = new ArrayList();
    UriData uri2 = new UriData("http://examplesite/images/exampleimage2.jpg", "Image Description");
    imageUris.add(uri2);

    // Define Info Module
    List row0cols = new ArrayList();
    LabelValue row0col0 = new LabelValue("Next Reward in","2 coffees");
    LabelValue row0col1 = new LabelValue("Member Since", "01/15/2013");
    row0cols.add(row0col0);
    row0cols.add(row0col1);

    List row1cols = new ArrayList();
    LabelValue row1col0 = new LabelValue("Local Store", "Mountain View");
    row1cols.add(row1col0);

    List rows = new ArrayList();
    LabelValueRow row0 = LabelValueRow.newBuilder().setHexBackgroundColor("#922635")
        .setHexFontColor("#F8EDC1").addColumns(row0cols).build();
    LabelValueRow row1 = LabelValueRow.newBuilder().setHexBackgroundColor("#922635")
        .setHexFontColor("#F8EDC1").addColumns(row1cols).build();

    rows.add(row0);
    rows.add(row1);

    // Define general messages
    List messages = new ArrayList();
    WalletObjectMessage message =  WalletObjectMessage.newBuilder()
        .setHeader("Hi Jane!")
        .setBody("Thanks for joining our program. Show this message to " +
            "our barista for your first free coffee on us!")
        .setImageUri(
            new UriData("http://examplesite/images/exampleimage1.jpg",""))
        .setActionUri(new UriData("http://baconrista.com",""))
        .build();
    messages.add(message);

    // Define Geolocations

    LatLng location = new LatLng(37.422601, -122.085286);

    List locations = new ArrayList();
    locations.add(location);

    LoyaltyWalletObject wob = LoyaltyWalletObject
        .newBuilder()
        .setClassId("2967745143867465930.LoyaltyClass")
        .setId("2967745143867465930.LoyaltyObject")
        .setState(WalletObjectsConstants.State.ACTIVE)
        .setAccountId("1234567890")
        .setAccountName("Jane Doe")
        .setIssuerName("Baconrista")
        .setProgramName("Baconrista Rewards")
        .setBarcodeType("qrCode")
        .setBarcodeValue("28343E3")
        .setBarcodeAlternateText("12345")
        .setBarcodeLabel("User Id")
        .setLoyaltyPoints(points)
        .addTextModulesData(textModulesData)
        .addLinksModuleDataUris(uris)
        .setInfoModuleDataHexFontColor("#F8EDC1")
        .setInfoModuleDataHexBackgroundColor("#442905")
        .setInfoModuleDataShowLastUpdateTime(true)
        .addInfoModuleDataLabelValueRows(rows)
        .addImageModuleDataMainImageUris(imageUris)
        .addMessages(messages)
        .addLocations(locations)
        .build();

Offer Object

    public OfferWalletObject generateObject(){

        // Define Text Module Data
        List textModulesData = new ArrayList();
        TextModuleData textModuleData = new TextModuleData("Details", "20% off one coffee beverage." +
                "Offer valid 30 days from date of issue.  Not applicable with other offers.  Offer" +
                " must be presented at time of purchase.  Offer not valid on non coffee based beverages");
        textModulesData.add(textModuleData);

        // Define Links Module Data
        List uris = new ArrayList();
        UriData uri1 = new UriData("http://www.baconrista.com/myaccount?id=1234567890","My Baconrista account");
        uris.add(uri1);

        List imageUris = new ArrayList();
        UriData uri2 = new UriData("http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", "Image Description");
        imageUris.add(uri2);

        // Define Info Module
        List row0cols = new ArrayList();
        LabelValue row0col0 = new LabelValue("Next Reward in","2 coffees");
        LabelValue row0col1 = new LabelValue("Member Since", "01/15/2013");
        row0cols.add(row0col0);
        row0cols.add(row0col1);

        List row1cols = new ArrayList();
        LabelValue row1col0 = new LabelValue("Local Store", "Mountain View");
        row1cols.add(row1col0);

        List rows = new ArrayList();
        LabelValueRow row0 = LabelValueRow.newBuilder().setHexBackgroundColor("#922635")
            .setHexFontColor("#F8EDC1").addColumns(row0cols).build();
        LabelValueRow row1 = LabelValueRow.newBuilder().setHexBackgroundColor("#922635")
            .setHexFontColor("#F8EDC1").addColumns(row1cols).build();

        rows.add(row0);
        rows.add(row1);

        // Define general messages
        List messages = new ArrayList();
        WalletObjectMessage message =  WalletObjectMessage.newBuilder()
            .setHeader("Hi Jane!")
            .setBody("Thanks for being a great customer.")
            .setImageUri(
                    new UriData("http://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", ""))
            .setActionUri(new UriData("http://baconrista.com", ""))
            .build();
        messages.add(message);

        // Define Geolocations

        LatLng location = new LatLng(37.422601, -122.085286);

        List locations = new ArrayList();
        locations.add(location);
        Date time = new Date();

        OfferWalletObject wob = OfferWalletObject
            .newBuilder()
            .setClassId("2951238800106304306.OfferClassMonster3")
            .setId("2951238800106304306.OfferTestObject1")
            .setState(WalletObjectsConstants.State.ACTIVE)
            .setIssuerName("Baconrista")
            .setTitle("20% off coffee")
            .setValidTimeInterval(new TimeInterval(time.getTime(), time.getTime() + 144000000L))
            .setBarcodeType("qrCode")
            .setBarcodeValue("28343E3")
            .setBarcodeAlternateText("12345")
            .setBarcodeLabel("Coupon Code")
            .addTextModulesData(textModulesData)
            .addLinksModuleDataUris(uris)
            .setInfoModuleDataHexFontColor("#F8EDC1")
            .setInfoModuleDataHexBackgroundColor("#442905")
            .setInfoModuleDataShowLastUpdateTime(false)
            .addInfoModuleDataLabelValueRows(rows)
            .addImageModuleDataMainImageUris(imageUris)
            .addMessages(messages)
            .addLocations(locations)
            .build();

        return wob;
      }
    }

This object is the first parameter taken by the createWalletObject call described in the next section.

5. Save the object

Call the CreateWalletObjectsRequest method to save the object to the user's Google Wallet.

CreateWalletObjectsRequest request = new CreateWalletObjectsRequest(wob);
Wallet.createWalletObjects(googleApiClient, request, SAVE_TO_WALLET);

6. Handle onActivityResult

Define onActivityResult to react to the success, cancellation, or failure of the operation as shown:

public void onActivityResult(int requestCode, int resultCode, Intent data){
  EditText textBox = (EditText) findViewById(R.id.s2wResponse);

  switch(requestCode){
    case SAVE_TO_WALLET:
      switch (resultCode) {
        case Activity.RESULT_OK:
          textBox.setText("saved");
          break;
        case Activity.RESULT_CANCELED:
          textBox.setText("canceled");
          break;
        default:
          int errorCode =
              data.getIntExtra(
                  WalletConstants.EXTRA_ERROR_CODE, -1);
          textBox.setText("failed error code: " + errorCode);
          break;
      }