Publish 2 Android apps with same code but different design

Android APK logo

While I was developing games for Firezoo, I faced a problem that many Android developer might have faced before me: How to publish two different apps with the same code base but different design without duplicating the project/source code?

Indeed, in Eclipse, it’s not possible to select what you want in your apk (specific resources, assets) when you export your Android application project. Plus you will need to have different name for the application in AndroidManifest.xml and even some minor code changes depending of the app design.

I will explain below the solution I chose while I was developing this two apps, if you have any suggestions or better ideas, feel free to let me know. The code is free to use by anyone.

Differences in files

The first problem was differences in certain files like AndroidManifest.xml, string.xml, java files or even c++ files if using NDK.

As I’m using Git as a source control, I thought of creating a different branch for my second app (NewDesignApp) while my main app (MainApp) will stay on the master branch.

Changes that needed to be made for the second app will be on the NewDesignApp branch, for example changing code, changing string used, add precompiler argument for C++ code (NDK), etc. Every time the MainApp will evolve on the master branch, it will be merged into the NewDesignApp branch, letting the second app benefit all bug corrections and features that the MainApp receives. But be careful, the NewDesignApp branch will NEVER be merged back into the master branch (MainApp), it will live forever on its own and the master branch will never be aware of a second app.

When you are ready to export one app or the other, you just have to change branch on Git ($git checkout NewDesignApp), clean Eclipse project (Project → Clean) and export your app in a specific repository.

Repack APK to remove unused resources

The second problem problem appears during the export, it’s impossible on Eclipse to choose which files you want to export in your APK and you need to pack all files present in assets and res folders. You could manage to get away from it with Git branches like explain before, but one thing very important is that your package name need to be different for each of your App (APK). For that, you will need to use a script to unpack and repack your APK with the package rename and just the files you want (apk size always matter on mobile).

The script below is a Shell Script that can be used on Linux or Mac in a terminal, but also on Windows with MinGW or Cygwin.

Tools needed:

  • Java 1.7 (JRE 1.7) to use the APK tool and Jarsigner
  • Android SDK to use aapt and Zipalign.
  • ApkTool to unpack and repack APK (https://code.google.com/p/android-apktool/)

The aapt command need to be in the PATH for ApkTool to works correctly (e.g. sdk\build-tools\19.1.0). You can also move the aapt executable to your Repacking directory.
When this article was written, ApkTool version 2 was not released, I use currently the beta 9 (v2.0.0b9).

On Windows

This image shows what the Repacking repository will look like on Windows

We will now see in details, what the Repack.sh contains:

#!/bin/sh
# APK repacking script
OriginalAPK=$1.apk
FinalAPK=$2.apk
APKFolder=apk
Manifest=AndroidManifest.xml
InputFolder=input
OutputFolder=output
APKTool=apktool_2.0.0b9.jar

# Cleanup previous packaging
if [ -d "$APKFolder" ]; then
    echo Cleanup $APKFolder folder
    rm -r $APKFolder
fi

The $1 and $2 refer to arguments of the command line when running the script. The script could be run in the command line like this: $./Repack.sh NewDesignApp New\ Design\ App. The APKFolder is the folder where the APK will be unpack then repack, it is also clear if exist every time the script is run to avoid incremental build. InputFolder corresponds to the folder the APK was exported to from Eclipse, where OutputFolder is the directory where the new APK will be after the script has finished. APKTool is the name of the current version of the tool used.

# Unpack selected apk from input folder
echo Start unpacking $OriginalAPK into $APKFolder folder
java -jar $APKTool d $InputFolder/$OriginalAPK -o $APKFolder
echo Finish unpacking

Then come the unpack process, nothing special here.

# Change apk content depending on App type (MainApp, NewDesignApp, etc.)
if [ $1 = "MainApp" ]; then
    echo Rename package name in $Manifest
    sed -i -e 's/com.company.mainapp/com.company.newdesignapp/g' $APKFolder/$Manifest
    echo Rename package name in smali directory
    mv $APKFolder/smali/com/company/mainapp $APKFolder/smali/com/company/newdesignapp
    echo Rename package occurences in each files, can take some time...
    find $APKFolder/smali -type f -name *.smali -exec sed -i -e 's,company/mainapp,company/newdesignapp,g' {} \;
    echo Delete unnecessary assets
    AssetDir=MainApp
    rm -r $APKFolder/assets/$AssetDir
    rm $APKFolder/assets/api_key_MainApp.txt
elif [ $1 = "NewDesignApp" ]; then
    echo Delete unnecessary assets
    AssetDir=NewDesignApp
    rm -r $APKFolder/assets/$AssetDir
    rm $APKFolder/assets/api_key_NewDesignApp.txt
else
    echo "App not supported"
    exit 0
fi

Here is the most important part of the process, it’s to rename the correct files and their contents to change the java package name. Indeed, because the Play Store and Java in general recognize an APK based on it’s package name, it’s not possible to publish two applications with the same package name, which is why it needs to be renamed here in the Manifest file and in the smali files.

Then you might want to delete some assets or resources that are not used for a specific version, or even removing the api key of the other app version. You just need to remove this files from the apk folder before repacking.

# Repack apk and move it to output folder
echo Start repacking $OriginalAPK
java -jar $APKTool b $APKFolder
echo Finish repacking
echo Move final apk in $OutputFolder
if [ ! -d "$OutputFolder" ]; then
    echo Create $OutputFolder folder
    mkdir $OutputFolder
fi
mv $APKFolder/dist/$OriginalAPK $OutputFolder/$OriginalAPK

Then starts the repacking and the final APK is moved to the output folder.

# Sign and ZipAlign apk
echo Sign apk with keystore
jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore "androidkey" -storepass "mypassword" -keypass "mypassword" $OutputFolder/$OriginalAPK myandroidkey
echo Verify signing
jarsigner -verify -certs -keystore "androidkey" $OutputFolder/$OriginalAPK
if [ -f "$OutputFolder/$FinalAPK" ]; then
    echo Remove existing file : "$OutputFolder/$FinalAPK"
    rm "$OutputFolder/$FinalAPK"
fi
echo ZipAlign to a new apk : $FinalAPK
zipalign 4 "$OutputFolder/$OriginalAPK" "$OutputFolder/$FinalAPK"
rm "$OutputFolder/$OriginalAPK"

exit 0

To end the process and obtain an APK similar to the one you could get from Eclipse export feature, you will need to sign the APK with your SHA1 key, verify the signing and zipalign the APK.
“androidkey” is the name of the key store (also name of the file), “myandroidkey” is the name of the key for this specific app. It is recommended by Google to sign all the app of a same company with the same key.

You should now have a fresh apk to test on your device (using adb) and then publish on your favorit store.