ninjinkun's diary

ninjinkunの日記

Build Variantsで開発版Androidアプリを分ける

f:id:ninjinkun:20140818095759p:plain

Androidアプリを開発していると、開発版とリリース版のアプリを同時に入れておきたいことがあると思います。通常Appliction ID (com.ninjinkun.njkappのようなやつ) が同一だとアプリが上書きされてしまうのですが、Build Variantsを使う事で別のApplication IDを割り振ることができます。

build.gradle

productFlavors {
    staging {
        setApplicationId("com.ninjinkun.njkapp.staging")
    }
    production {
    }
}

Manifest Placeholder

この辺りは去年からできたのですが、 ContentProviderBroadcastReceiver を使っている場合、Android ManifestにApplication IDが文字列で埋め込まれており、自動的に置換されずにインストール時にエラーが出てしまう問題がありました (com.ninjinkun.njkappに対応するアプリケーションはないという感じの文句が出た記憶) 。しかし今年の4月下旬にリリースされた Manifest Manager のPlaceholder機能を使って、Android Manifestに変数が埋め込めるようになりました。以下のように設定することで、エラー問題が解決できます。

AndroidManifest.xml

<provider
    android:name="com.ninjinkun.njkapp.NJKProvider"
    android:authorities="${applicationId}"
    android:exported="false" />

Placeholderの応用

また、build.gradleで自由に変数を定義することもできます。これを使う事で、開発用アプリを別名にできます。

build.gradle

defaultConfig {
     manifestPlaceholders = [appName:"@string/app_name"]
}

productFlavors {
    staging {
        manifestPlaceholders = [appName:"@string/app_name_staging"]     
    }
    production { }
}

AndroidManifest.xml

<application
        android:name="com.ninjinkun.njkapp.Application"
        android:icon="@drawable/ic_launcher"
        android:label="${appName}" >
        <activity
            android:name="com.ninjinkun.njkapp.MainActivity"
            android:label="${appName}"
            android:launchMode="singleTop"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
      </activity>
...

category.LAUNCHAERになっているActiviyのlabelを変更しないとランチャーでのアプリ名が変わらないのに注意。AndroidManifestを自由に書き換えられるので、アプリアイコンを変えることもできると思います。

BuildConfigField

サーバーの本番/開発機を振り分けるために、以下のbuildConfigFieldを設定しています。

build.gradle

productFlavors {
    staging {
        buildConfigField "boolean", "SERVER_PRODUCTION", "false"
    }
    production {
        buildConfigField "boolean", "SERVER_PRODUCTION", "true"
    }
}

コードから使うときは以下のようにBuildConfigクラスの定数として参照できます。

public String getHost() {
    if (BuildConfig.SERVER_PRODUCTION) {
        return context.getString(R.string.host_production);
    } else {
        return context.getString(R.string.host_staging);
    }
}

まとめ

以上の設定をまとめて、仕事で使っているbuild.gradleBuild Variantsまわりはだいたい以下のようになっています (名前空間だけ変えました)。

build.gradle

defaultConfig {
     manifestPlaceholders = [appName:"@string/app_name"]
}

productFlavors {
    staging {
        setApplicationId("com.ninjinkun.njkapp.staging")
        buildConfigField "boolean", "SERVER_PRODUCTION", "false"
        manifestPlaceholders = [appName:"@string/app_name"]
    }
    production {
        buildConfigField "boolean", "SERVER_PRODUCTION", "true"
    }
}

補足: Build Variantsについて

ビルド構成を決めるBuild Variantsについては先ほどのnobuokaさんの記事に詳細な解説があるので、ここでは簡単な説明だけしておきます。

Build VariantsはProduct FlavorsBuild Typesの組み合わせで表現されます。

  • Product Flavors
    • アプリに別名を付けたり、一部を変更したりしてリリースする為の仕組み
    • Flavor毎にAndroidManifestやリソースを持つことが出来る
    • manifestPlaceholdersが使える
      • アプリ名などを変更可能
  • Build Types
    • アプリのビルド設定を切り替えるための仕組み
    • デフォルトではdebug / releaseが用意される
    • releaseでビルドすると最適化や圧縮が行われる

Product Flavorsがstaging/production、Build Typesがdebug/releaseだと以下の様に組み合わせから選べるようになります。

スクリーンショット 2014-07-22 17.25.35.png

2014/9/5 追記

manifestPlaceholdersはただの変数なので、設定を追加したい場合はハッシュの後ろに追記する必要があります。

manifestPlaceholders = [appName:"@string/app_name", gaCode:"@string/ga_code"]