viernes, 18 de octubre de 2013

Automatic app creation and binary upload

So, you finally realized that all the apps you are doing are very similar. They all have some many things in common that you created a pool of parts from where you pickup the ones you need for you next project and compile all together. If you are as lazy as I am, you probably made all of this automatic so you only needs to select the modules needed and everything else is made by your steward (mine is called Jenkins).

The problem now is that you cannot upload your new and shinny app automatically to the store. There's a tool from Apple (iTMSTransporter) to make lots of things automatically but not the creation of the app profile. I was looking for a tool that helped me with this task and I found itc.cli, a great tool indeed, but it doesn't do all I needed. What to do in this cases? Easy: modify it to fit your needs (and share the changes so everybody can benefit from them). So here is my version: https://github.com/diegopeinador/itc.cli

With this two tools I could create a script to upload apps automatically to the AppStore. Deatails are as follow:

First, we need to create the App profile in the AppStore. For that we can use itc.cli. It needs a config file with all the information for the profile (sure you can get all of this from your database, and create this file automatically). Config file example:
{"config": {
    "images": {"file name format": "app_data/{device_type}/{index}.png"},
    "device type aliases": {
      "ipad": "iOS-iPad",
      "iphone": "iOS-3.5-in",
      "iphone 5": "iOS-4-in"
    }},
  "application": {
    "new app": {
      "default language": "en",
      "name": "Test App",
      "sku number": "myOwnIdentifier",
      "bundle id": "com.my.company.*",
      "bundle id suffix": "myOwnIdentifier",
      "availability date": "Jan 01 2014",
      "countries": {},
      "price tier": 0,
      "discount": false,
      "version": "1.0",
      "copyright": "Me",
      "primary category": "Productivity",
      "app rating": [0,0,0,0,0,0,0,0,0,0],
      "large app icon": {"file name format": "app_data/icon.png"},
      "screenshots": {"iphone": [1,2,3,4,5],"iphone 5": [1,2,3,4,5]},
      "description": {"file name format": "app_data/description.txt"},
      "keywords": "test,keywords,deleteme",
      "support url": "http://my.company.com/support",
      "marketing url": "http://my.company.com",
      "privacy policy url": "http://my.company.com/policy"
    },
    "app review information": {...}}}
And then run the tool with the commandline:
/usr/local/bin/itc create -c /apps/upload/myOwnIdentifier.json -v --username email@address.com --password myS3cr3tPassw0rd
This will create a profile for your app in the AppStore. Now, we need to upload the binary, and can be done easily with iTMSTransporter, except for one thing: you need to setup the app in the waiting for upload state before you make use of the transporter. That's probably because of that stupid question from the US Export Regulations: Does your app use cryptography?

If your apps are simple and you always select NO in that question you can use my modified version of itc.cli to do that automatically:
/usr/local/bin/itc binary -a APPLE_ID --username ...
But, now we have a problem, we don't know the APPLE_ID of the newly created app. Well, you can use iTMSTransporter to get it:
/usr/local/bin/iTMSTransporter.woa/iTMSTransporter -u email@address.com -p myS3cr3tPassw0rd -v off -m lookupMetadata -vendor_id myOwnIdentifier -destination /tmp/ >/dev/null 2>&1 && cat /tmp/myOwnIdentifier.itmsp/metadata.xml | grep apple-id | cut -d ">" -f2 | cut -d "<" -f1
And, finally, we can upload the binary. For that we'll need a config file like this:
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://apple.com/itunes/importer" version="software5.1">
    <provider>
        yourProviderName
    </provider>
    <team_id>
        VGV19P6YWPL
    </team_id>
    <software>
        <vendor_id>
            myOwnIdentifier
        </vendor_id>
        <software_assets>
            <asset type="bundle">
                <data_file>
                    <size>
                        23463465
                    </size>
                    <file_name>
                        myOwnIdentifier.ipa
                    </file_name>
                    <checksum type="md5">
                       
af069088b06c4062f5b680654b434492
                    </checksum>
                </data_file>
            </asset>
        </software_assets>
    </software>
</package>
The command line for this last step:
/usr/local/bin/iTMSTransporter.woa/iTMSTransporter -u email@address.com -p myS3cr3tPassw0rd -m upload -v critical -t Aspera,Signiant -k 100000 -f /apps/upload/itms/ -success /apps/upload/success -failure /apps/upload/failed -loghistory /apps/upload/logs/iTMSTransporter.log -errorLogs /apps/upload/logs/errors
This will upload all packages in the /apps/upload/itms/ directory and move them to the success or failed directories as the result of the upload.

As a summary, you can put everything together in a script:
#!/bin/bash
APP_ID=$1
# Create JSON config file:
/usr/local/bin/access_DB_and_build_JSON > /apps/upload/$APP_ID.json
# Create a new profile in AppStore:
/usr/local/bin/itc create -c /apps/upload/$APP_ID.json -v --username email@address.com --password myS3cr3tPassw0rd
# Get the apple_id of the new app
APPLE_ID=`/usr/local/bin/iTMSTransporter.woa/iTMSTransporter -u email@address.com -p myS3cr3tPassw0rd -v off -m lookupMetadata -vendor_id myOwnIdentifier -destination /tmp/ >/dev/null 2>&1 && cat /tmp/myOwnIdentifier.itmsp/metadata.xml | grep apple-id | cut -d ">" -f2 | cut -d "<" -f1`
# Change status of the app
/usr/local/bin/itc binary -a $APPLE_ID --username email@address.com --password myS3cr3tPassw0rd
# Create XML config file:
/usr/local/bin/access_DB_and_build_XML > /apps/upload/itms/$APP_ID.itmsp/metadata.xml
# upload binary
/usr/local/bin/iTMSTransporter.woa/iTMSTransporter -u email@address.com -p myS3cr3tPassw0rd -m upload -v critical -t Aspera,Signiant -k 100000 -f /apps/upload/itms/ -success /apps/upload/success -failure /apps/upload/failed -loghistory /apps/upload/logs/iTMSTransporter.log -errorLogs /apps/upload/logs/errors
I hope you find this useful. Any questions or comments?

3 comentarios:

  1. Hi Diego

    I read your article. It is very helpful for me. :)
    But now I have only one question.

    I tried to upload binary file.
    But I got following errors.

    "software_assets" not allowed here; expected the element end-tag at XPath /package/software/software_assets

    Can you help me?

    Thanks
    Meng

    ResponderEliminar
  2. I just implemented all this into an open source ruby gem: https://github.com/KrauseFx/deliver

    Just provide the path to your ipa file, screenshots or whatever you want to upload and deliver will take care of generating the correct xml file for you and upload it to Apple.

    ResponderEliminar