Showing posts with label Google Play. Show all posts
Showing posts with label Google Play. Show all posts

27 October 2019

Enrol on App Signing in the Google Play Store for existing Android App

App Signing by the Google Play Store is on the face of it an incredibly brilliant idea. I absolutely love it. However I found it impossibly difficult to follow Google’s rather short documentation on how to get setup, especially for existing app users. So I thought I’d write this little helper to try and spell it out to anyone who tries to follow the same process I have.

App signing is the process of creating a keystore with which you sign your Android app and verify it is in fact you who is releasing an update to your Android app. A keystore remember is basically just a special store for a private and a public key.

If you lose the original master keystore you signed your app with, bad news. You need to create a new app and a new Google Play Store listing. Not fun.

The concept of App Signing for Google Play Store is basically that you surrender the master keystore that you used to sign your initial app to Google (let’s call this the release key). Google then securely stores and manages your release key. You then create a brand new keystore called an upload key. You do this as if you were creating a brand new app, through Android Studio or if you’re a keyboard warrior, using java keytool. You then tell Google about this upload key and you’re done. All future releases can be signed with your upload key and Google will re-sign with the original, now super secret and secure release key. The benefit of this is Google keeps everything secure, and if you lose or compromise your upload key, Google will let you discard it and create a new one. Your users are none the wiser and everyone is happy all of the time.

The process for implementing all this is a little more complicated, first you need to head the play store and goto “App signing” under “Release management”.




Now we need to get all our keystores, private keys, certificates and koala bears in some sort of order. I’m doing this in Android Studio 3.5, older versions may need an upgrade.

First step we need to extract the private key from your original master release key.

Step 1 - Get an App Signing Private Key

Open your app in Android Studio and ensure it builds

  1. Goto Build -> Generate Signed Bundle / APK (Don’t worry you don’t need to actually release this build)
  2. Even if you’re not wanting to use App Bundle, select Android App Bundle and click next.
  3. Enter the details for your master, original release key, including store password, alias and key password
  4. IMPORTANT -> check “Export encrypted key for enrolling published apps in Google Play App Signing”
  5. Finish off the process and make a build. You should now have a pepk file which is the private key for your original master release key.


Now we need to generate a brand new upload key to use to sign our future apps.

Step 2 - Create an upload key


  1. Again goto Build -> Generate Signed Bundle / APK (Again not actually going to release an app)
  2. Select APK or App Bundle, whichever you would normally do.
  3. Click “Create new…”, we’re going to create a new keystore.
  4. Fill in all the details and make the build.
  5. You should now have a brand new keystore with brand new passwords and an alias. KEEP THIS CAREFULLY.
  6. This keystore will be used forevermore as your main key to release your apps.


Now we need to get a public key from our new upload key, this will be how we tell Google about our new upload key.

Step 3 - Generate a Public Certificate


  1. Use keytool and run a command like this
    keytool -export -rfc -keystore upload-keystore.jks -alias upload -file upload_certificate.pem
  2. Use your NEW UPLOAD KEY for “upload-keystore.jks” and your new alias 
  3. Keytool is usually somewhere in jdk/bin
  4. After running this command you should have a .pem file.


Now go back to the Google Play Store and click “Upload a key exported from Android Studio” now you can add your private key and your public certificate. This gives Google the details of the release key and the upload key and you should be all set.

Click finish and you should now be signed up to App Signing. Well done, keep a close eye on that upload key and it’s passwords.

05 December 2014

Lollipop update for Nexus 7 (2012) - Update


I previously blogged about problems with Lollipop on my Nexus 7. After quite a few emails with Google Play support I have been promised that an update to fix this issue began roll out globally on 3rd December. So fingers crossed the many upset users out there will shortly have the problem solved. Well done Google (assuming it works).

25 January 2014

Google Cloud Messaging with Android and ColdFusion backend


Google Cloud Messaging (GCM) is an awesome little service. It enabled "push" messages to be sent from Google to a specific Android phone and picked up by your application. The scope for these messages is massive but the intent is for the content to be fairly small. A great example (and a great name) is a tickle. This is very small message intended to instruct the application to go and perform an action.

For example, say your app needs data to be kept in sync with your server. This could be done by polling, but polling is resource intensive and sucks up precious bandwidth. A far better idea would be for your server to send out a message whenever the necessary data is updated and tell your app to come and re-fetch the data when possible. The message sent to your app is called a tickle!

I've created a simple tutorial to briefly describe GCM and show an example. My example does have a lot of moving parts to it but hopefully is simple enough to get the basic idea. For my backend server I'm using a CFML server which keeps track of any device registering for messages and allows me to send a message out too that device.

The sample app uses three components:

  1. GCM Connection Server - A Google Cloud project to send the message from you to the device.
  2. Application Server - Your own personal server that tracks device ids and issues messages. This can be cfml, php aspx, whatever, but it needs the capacity to store data, preferably in a db.
  3. Your Android app - The app you write and distribute as necessary.

Step 1 - The GCM Server

OK First we need to setup our Google Cloud Messaging service. To do this we log onto Google's cloud messaging panel and configure a new project. This project will now sit and wait for instructions and when told will relay messages from our server to our elected android device.

To set this up, follow the instructions here: http://developer.android.com/google/gcm/gs.html

Step 2 - The Application Server

As mentioned for this I'm using CFML here with a mysql db. I've not spent much time on this so it doesn't look pretty but I just wanted to illustrate the point. First the db, I've used one simple table:

CREATE TABLE gcmtest{
 intID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 strName varchar(100) not null,
 registrationid varchar(200) not null
}

That's it for db work! We have an ID column, a human readable name and a registration id which will contain the device id which is registered with Google.

Now the application server needs two files. One to respond to incoming registration requests and one to send messages, first the registration responder. Now a word of warning, this isn't production worthy, it's just a test bed. You should sanitise and protect your data much more thoroughly. As you can see it takes two values from the URL and inserts them into the db.

receive.cfm:
<cfif structKeyExists(url, "registrationid") AND structKeyExists(url, "name")>

    <cfquery name="qInsertReg" datasource="local">
        insert into gcmtest 
        (
            registrationid,
            strname
        )
        values
        (
            <cfqueryparam cfsqltype="CF_SQL_VARCHAR"    value="#url.registrationid#" />,
            <cfqueryparam cfsqltype="CF_SQL_VARCHAR"    value="#url.name#" />
        )
    </cfquery>

    <cfoutput>Done.</cfoutput>

</cfif>

Next you need the page which will send out messages, send.cfm:


<cfif structKeyExists(url, "regid")>

    <cfif structKeyExists(url, "strmsg")>
        <cfset strmymsg = url.strmsg />
    <cfelse>
        <cfset strmymsg = "all your base are belong to me" />
    </cfif>

    <cfset stFields = { "registration_ids": [ "#url.regid#" ], "data": {msg: "#strmymsg#"} }>
    
    <cfhttp url="https://android.googleapis.com/gcm/send" method="post" result="httpResp" timeout="60">
        <cfhttpparam type="header" name="Content-Type" value="application/json" />
        <cfhttpparam type="header" name="Authorization" value="key=***yourkeyfromgoogle***" />
        <cfhttpparam type="body" value="#serializeJSON(stFields)#">
    </cfhttp>
    
        
    <cfif httpResp.status_code eq 200>
        <span style="color:green;font-weight:bold;">Message Sent</span><br />
    </cfif>
</cfif>


<cfquery name="qGet" datasource="local">
    select * from gcmtest
</cfquery>

<form action="send.cfm" method="GET">
    <strong>Select Recipient:</strong>
    <br />
    
    <cfoutput query="qGet">
        <input type="radio" name="regid" value="#registrationid#">#strname#<br>
    </cfoutput>
    <br />
    
    <strong>Message:</strong><br />
    <input name="strmsg" type="text" /><br /><br />
    <input type="submit" value="submit" name="submit">
</form>

As you can see, we get everything from the gcmtest table and output it with radio buttons and a message box. When you hit send it self posts and the cfhttp takes over. For the cfhttp we use a json struct containing the registration id and the message. This we pass to the url https://android.googleapis.com/gcm/send obviously not forgetting to pass along our authorization key we created in step one.

That's it for the server side!

Step 3 - Android In Action

Now we need to have our Android app a) register with and b) receive messages from CGM. Now there is a lot of code here, so I'll post the project on gitHub but I'm hoping to cover the basics. There are obviously loads of things you can do with this message but for now I'm just going to use the basic Google demo method of posting a notification. To do this we register a WakefulBroadcastReceiver which will keep the device alive in case it hears a broadcast message. Then it will fire an intentService.

a) Manifest.xml
You need these permissions:

    <!-- GCM connects to Google Services. -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <permission android:name="com.google.android.gcm.demo.app.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.google.android.gcm.demo.app.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

You also need to register the services:


<receiver
      android:name=".GcmBroadcastReceiver"
      android:permission="com.google.android.c2dm.permission.SEND" >
          <intent-filter>
               <!-- Receives the actual messages. -->
               <action android:name="com.google.android.c2dm.intent.RECEIVE" />
               <category android:name="com.google.android.gcm.demo.app" />
          </intent-filter>
</receiver>
<service android:name=".GcmIntentService" />

Then what we're going to do in ActivityMain is check for the existence of a stored preference for the users name. If found we'll start a Fragment to welcome the user, if not we'll ask the user for their name.


FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
String strName = getNameFromPrefs();

if(strName.length() > 0){
 Bundle bundle = new Bundle();
 bundle.putString(FragmentWelcome.TAG_NAME, strName);
 FragmentWelcome frag = new FragmentWelcome();
 frag.setArguments(bundle);
 ft.replace(R.id.activity_default_fragment_container, frag, FragmentWelcome.class.getSimpleName());
}else{
 ft.replace(R.id.activity_default_fragment_container, new FragmentName(), FragmentName.class.getSimpleName());
}

ft.commit();

Now FragmentName is really simple and I shall spare you the details. It is a simple layout with an input text box. It checks for internet and validates the input and if so it calls a listener which returns to the main activity. The Activity saves the user's name in the savedPreferences and opens FragmentWelcome.

FragmentWelcome covers the following steps:
  • Get user's name via intent
  • verify GooglePlayServices
  • Gets your GCM Sender ID (created in step 1). Store this in strings.xml or somewhere sensible.
  • Using your GCM Sender ID it posts to Google Play Services and gets your device id.
        private void registerInBackground() {
            new AsyncTask<String, Void, String>() {
                @Override
                protected String doInBackground(String... params) {
                    String msg = "";
                    String name = "";
                    try {
                        if (gcm == null) {
                            gcm = GoogleCloudMessaging.getInstance(context);
                        }
                        regid = gcm.register(SENDER_ID);
    

  • Gets the URL of the receieve.cfm file we created in step 2 (again store it in strings or prefs) and appends the user's name and the device id to the url.
  • Call an AsyncTask to open DefaultHttpClient and hit the url we have now created.
        private class UploadRegistrationID extends AsyncTask<String, Void, String> {
            @Override
            protected String doInBackground(String... urls) {
                String response = "";
                for (String url : urls) {
                    DefaultHttpClient client = new DefaultHttpClient();
                    HttpGet httpGet = new HttpGet(url);
                    try {
                        HttpResponse execute = client.execute(httpGet);
                        InputStream content = execute.getEntity().getContent();
        
                        BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
                        String s = "ServerResponse:";
                        while ((s = buffer.readLine()) != null) {
                            response += s;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return response;
            }
    

That's it. Once you've run your Android app and entered your name you should be able to go to your send.cfm file in a web browser and send a message through to your device. The message will then pop up in your notification window!

Here's the Android project on github:
https://github.com/jamessolo12/gcmPushDemo

Magic ;)






24 July 2013

Google Play Game Services


I've previously created my own custom built high scores add on for my Android app, frankly it was pretty rubbish. It was local only, not very pretty and had no public competition element. There are a few third party apps but they cost money. That is until at Google IO Google announced Google Play Game Services. I thought I'd take a look and I was incredibly impressed.

http://developer.android.com/google/play-services/games.html

Game Services allows you to instantly integrate a leaderboard into your app. It does this using Google + which means your users can share their scores with their circles, specific friends or of course with the public. I love this because just thinking about creating a user id for every user and a server side backend to deal with all that makes me shudder. Plus you can add in achievements which is pretty cool too.

So if you want to get started adding play services I very much recommend downloading Google's sample app "Type-a-Number":

https://developers.google.com/games/services/android/quickstart

Then run through the steps to get the API set-up on Google's developer console and of course provides a sample app and code to study. I really recommend you study this and get a good grasp on how it all works. I'm not going to run through all the code here, as Google have already done that. The same applies to the API, you do need to do a bit of setup on Google's developer console. Just make sure you copy the IDs of your game service and your leaderboard into your android project. Preferably in the same way Google suggest with an ids.xml file.

You're going to need to set-up eclipse and your project with Google Play Services Library which I already had for Google Maps anyway. The sample app uses the Base Game Utils library, which isn't totally necessary, but it does make things a little simpler. Again, all steps are covered in the quickstart.

The first thing is to get the Google Plus button working. This is a simple case of adding in the com.google.android.gms.common.SignInButton button to your layout file.
Then add a listener:

//Listener for Sign in
findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        beginUserInitiatedSignIn();
    }
});

Now beginUserInitiatedSignIn() is a function in Base Game Utils which deals with the Google + magic. It does have a callback function though which you can utilise, here's mine:

@Override
public void onSignInSucceeded() {
    Toast.makeText(this, "Signed in", Toast.LENGTH_SHORT).show();
    
    mShowSignIn = false;
    updateUi();

}

UpdateUi() handles hiding the sign in button and showing the sign out button.

Last but not least we need to push our scores.

getGamesClient().submitScore(getString(R.string.leaderboard_highscores),intScore);

It's spectacularly easy to do.

There are however a few things I've learnt:
  1. Be very wary of your certificate. You'll need to make sure the SHA1 hash you use is the same you export your Android project as the one you enter on the game services API.
  2. When you come to release this, if you've been using your debug certificate you'll need to delete your game services on the API and start it all over again. I've tried many times to tweak the SHA1 in an active game service but it always breaks. So best to start fresh with a production ready certificate and use it for the API as well.
  3. The IDs you get from play services must be copied exactly to your ids.xml file and your manifest must have a line like this:
    <meta-data android:name="com.google.android.gms.games.APP_ID" android:value="@string/app_id" />

  4. If you want to delete your scores or change the IDs you use for the game services or leaderboard you need to goto:
    Settings -> Google -> Google + -> Apps With Google + Sign In -> xx_AppName_xx -> Disconnect App
    You'll get the option here to delete your scores. This can be a bit temperamental, so change IDs only if you're really stuck.

One last thing worth mentioning, and its addressed to Google, whom I'm sure study my blog every day! When one looks at the achievements board, you can't expand the achievement to get the full description of what is required. On a phone, this means you'll never know what's required.

Thanks and good luck.