woensdag 25 mei 2016

Robolectric + Google Play Service (GMS)

When you are building Android application, you frequently use the services offered by Google Play. These libraries require you to define the version of the library in the Android Manifest:


...
    <application
        android:name="..."
        android:icon="@mipmap/ic_launcher"
        android:label="@string/application_name"
        android:logo="@drawable/ic_stat_notification"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />;
...


If you are using Robolectric 3.x (or before, I can't recall if the problem persists in prior versions too), you might end up with failing tests as Robolectric is not able to retrieve the value for @integer/google_play_services_version during the test run.
If you are using a custom RobolectricTestRunner for your test as I am, you can actually update the value when you are loading your Android manifest.

...
public class RobolectricGradleTestRunner extends RobolectricTestRunner {

    public RobolectricGradleTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override
    protected AndroidManifest getAppManifest(Config config) {
        AndroidManifest appManifest = super.getAppManifest(config);
        FsFile androidManifestFile = appManifest != null ? appManifest.getAndroidManifestFile() : null;

        if (null == androidManifestFile || !androidManifestFile.exists()) {
            String moduleRoot = getModuleRootPath(config);

            androidManifestFile = FileFsFile.from(moduleRoot, "src/main/AndroidManifest.xml");
            FsFile resDirectory = FileFsFile.from(moduleRoot, "src/main/res/");
            FsFile assetDirectory = FileFsFile.from(moduleRoot, "src/main/assets");

             appManifest = new AndroidManifest(androidManifestFile, resDirectory, assetDirectory, "be.acuzio.myapp");
        }

        final Map applicationMetaData = appManifest.getApplicationMetaData();

        for(String k : applicationMetaData.keySet()) {
            if("com.google.android.gms.version".equals(k)) {
                System.out.println("GMS version currently contains: <" + applicationMetaData.get(k) + ">");

                applicationMetaData.put(k, "8487000");
            }
        }

        return appManifest;
    }

    private String getModuleRootPath(Config config) {
        String moduleRoot = config.constants().getResource("").toString().replace("file:", "");
        return moduleRoot.substring(0, moduleRoot.indexOf("/build"));
    }
}
...