Publishing private enterprise apps to the managed Google Play Store

Here’s a quick how to guide for publishing a private app to the managed Google Play store using the Custom App Publishing API and then surfacing it to your enterprise users through your EMM/MDM solution.

When you use this API your apps are;

  • permanently private, meaning they can't be made public
  • not subject to the public Google Play Store policies such as API target levels, application permission restrictions, etc
  • going through a streamlined verification process and appear in the managed Google Play Store in as little as five minutes, compared to over two hours via the Play Console
  • The only store listing details required to publish an app are its title and default listing language.

Before you can run the code below you need to set up a service account that has permissions to publish private apps. You can follow the guide here to set it up.

  1. Enable the Google Play Custom App Publishing API
  2. Create a service account
  3. Obtain private app publishing rights
  4. Retrieve the developer account id

At the end of this step you will have created a service account (eg myappname@turnkey-crowbar-123456.iam.gserviceaccount.com) and retreieved your developer account id (eg 1234567890123456789).

Next you need to generate the private key that will be used to authenticate against the API. To do this click on the Create Key button in the Service Account details page and save the json file to your local disk (keep this key very secure).

Create private key for service account

Next fire up your favourite code editor, reference one of the pre-built Google API libraries (or directly use the REST API) to publish the app.

Here’s how I did it with Visual Studio.

Start a new console project and add a nuget reference to Google.Apis.Playcustomapp.v1.

Update the devAccountId, apkPath and clientSecretsJson variables in the code below and hit run. If all goes well the response returned is ‘Complete’. If you receive a ‘Failed’ response take a look in the exception message for why it could have failed.

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                new Program().Run().Wait();
            }
            catch (AggregateException ex)
            {
                foreach (var e in ex.InnerExceptions)
                {
                    Console.WriteLine("ERROR: " + e.Message);
                }
            }
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        private async Task Run()
        {
            long devAccountId = 1234567890123456789;
            var apkPath = @"C:\apps\MyPrivateApp.apk";
            var clientSecretsJson = @"C:\secrets\apppublishkey.json";

            var appMetaDda = new CustomApp
            {
                Title = "My Private Company App",
                LanguageCode = "en_AU"
            };

            GoogleCredential credential;
            using (var stream = new FileStream(clientSecretsJson, FileMode.Open, FileAccess.Read))
            {
                credential = GoogleCredential.FromStream(stream)
                    .CreateScoped("https://www.googleapis.com/auth/androidpublisher");
            }
          
            var svc = new Google.Apis.Playcustomapp.v1.PlaycustomappService(new Google.Apis.Services.BaseClientService.Initializer { HttpClientInitializer = credential });
            var request = svc.Accounts.CustomApps.Create(appMetaDda, devAccountId, File.OpenRead(apkPath), "application/octet-stream");
            var response = request.Upload();
            Console.WriteLine("Status = " + response.Status);
        }
    }

Remove the ms-outlook attribute added to your contacts

Like me if you had the unfortunate luck of using the Outlook app’s feature to sync your Gmail contacts to iOS and then used a sync app like Google Contacts sync you might have ended up with a whole bunch of contacts having an attribute called outlook with a value that says ms-outlook.

The fix is quite easy really. Using the awesome Script editor at https://script.google.com you can run this simple function to get rid of the stuff you don’t want.


function myFunction() {
  var contacts = ContactsApp.getContacts();
  for (var c = 0; c < contacts.length; c++) {
    var cnt = contacts[c];
    var fields = cnt.getUrls();
    for (var i = 0; i < fields.length; i++) {
      if(fields[i].getLabel() == "Outlook"){
        fields[i].deleteUrlField();
      }
    }
  }
}

PayID

Have you tried PayID yet? Given that you can only have one PayID identifier for each account and bank it doesn’t seem to make much sense to use your telephone number. Instead I’ve opted to use bankname@myemail.net (eg nab@myemail.net) thanks to the domain catch all feature in Google Apps. With gmail you could use the + alias (eg. nab+merill@gmail.com) or use the Outlook Alias feature where you can have multiple email addresses mapped to each account. Thanks to PayID I can now keep all of my income in the offset account and only transfer to my checking account at the very last minute. I tried transferring from my NAB account to ING and it come through even before I could switch between the two banking apps. Looking forward to shaving a few years off my mortgage. What approach have you come up with for PayID?

1163

The battle of the speakers has begun. My conundrum, one HomePod for $499 or two Sonos Ones for $349

Setting up WordPress as your micro blogging platform

Deciding on WordPress as your source of truth for your micro blog is all good but how do you avoid spamming your RSS readers with your status updates meant for micro.blog, twitter, linked in et al?

The simplest way to target WordPress posts for micro blogs is to use a specific category (I call mine status). You can then configure WordPress to not include posts from this category in the default feed.

One way to exclude a category from the default feed is using a re-write rule in your .htaccess file as shared by Manton in this gist https://gist.github.com/manton/f8b6f8b391a2f3d9b419

I wanted something a bit more robust that wouldn’t break when the url format changed. Instead I wrote a custom filter that would hide the category from the default feed. To get this set up you can use the excellent ‘My Custom Functions’ plug in https://wordpress.org/plugins/my-custom-functions/

https://gist.github.com/merill/92c71ffc980a1741ba1c4cc6900a3e5c

Once you have this set up you can now use the url to your feed as the feed source at https://micro.blog using the following format http://<<domain>>/category/<<category name>>/feed/

In my case this is my feed url http://merill.net/category/status/feed/

1137

❤️ the magical window of time during sunsets #nofilter #brightonbeach #iphone #amateurphotographer

1134

Google really wants to get as many Minis as it can into Australian homes before Alexa launches locally. The twin Google Mini packs are currently at $78. https://www.officeworks.com.au/shop/officeworks/p/google-home-mini-black-2-pack-sygmi2pkb