build.gradleの設定でパッケージ名のみ違うdebug.apkを作る上での注意点メモ
- はじめに
- 動作環境
- applicationIdSuffix を適応したときはどういう状態なのか?
- 桜さんのブログの記載箇所
- packageごとに、独自登録が必要なもの
- 独自ContentProvider の話
- adobe creative sdk(2018/03/01追記)
- 呼び出し側で気をつけること(2017/7/18追記)
- で問題となることは・・・
- 併用すると便利なライブラリ
はじめに
のお話なのですが、
- app/build.gradle
buildTypes { debug { debuggable true applicationIdSuffix ".debug" versionNameSuffix "-DEBUG" } }
をこのまま適応してしまうと、実行時にクラッシュエラーになる場合があるので、
どこを修正しないと駄目なのか辺りをちょっと整理してみました。*1
書き換えると、違うパッケージになるので楽だぜー な話しか見ないんですよね・・(汗
動作環境
applicationIdSuffix を適応したときはどういう状態なのか?
- AndroidManifest.xml のみ書き換わる
- class.jar 等はそのまま
書き換えられる箇所(ベース)
- 変更前
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="hoge.fuga.maiu"> <!--★-->
- 変更後
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="hoge.fuga.maiu.debug"> <!--★★-->
★ => ★★
物理package名 が補われるもの
android:name の場所は基本置き換えてくれるみたい
- 変更前
<activity android:name=".activity.MainActivity" android:screenOrientation = "portrait"> </activity> <service android:name=".service.MainService" android:exported="false"> </service>
- 変更後
<activity android:name="hoge.fuga.maiu.activity.MainActivity" android:screenOrientation = "portrait"> </activity> <service android:name="hoge.fuga.maiu.service.MainService" android:exported="false"> </service>
物理package名 が補われないもの
- meta-data
<-- meta-dataはフルパスにしておかないと駄目 (class.jarは変更されないため) --> <meta-data android:name="hoge.fuga.maiu.application.LimitCacheSizeGlideModule" android:value="GlideModule" />
桜さんのブログの記載箇所
GCMの箇所
ただGCMは現在新規登録できないので、古いアプリメンテ用の記載になるかも
- app/AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" /> <permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" /> <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <category android:name="${applicationId}" /> </intent-filter> <intent-filter> <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> <category android:name="${applicationId}" /> </intent-filter> </receiver>
FCMだと
上記あたりの記載は一切いらなくなる。移行は下記のページ参照
自動生成系
下記は、ManifestMarger時にマージされて付与される
<receiver android:exported="true" android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE"/> <category android:name="${applicationId}"/> </intent-filter> </receiver> <provider android:authorities="${applicationId}.firebaseinitprovider" android:exported="false" android:initOrder="100" android:name="com.google.firebase.provider.FirebaseInitProvider"/>
packageごとに、独自登録が必要なもの
google-play-service.json
MainP -- src/main -- google-services.json hoge.fuga.maiu 用 | -- src/debug | -- google-services.json hoge.fuga.maiu.debug 用
登録時のFinglerPrint
keytool -exportcert -list -v -alias androiddebugkey -keystore ./app/irof_history_debug.keystore
な感じで算出
facebook provider
MainP -- src/main/res -- config.xml hoge.fuga.maiu 用 [FacebookアプリID] | -- src/debug/res | -- config.xml hoge.fuga.maiu.debug 用 [FacebookアプリID]
- app/AndroidManifest.xml
<provider android:authorities="com.facebook.app.FacebookContentProvider[FacebookアプリID]" android:name="com.facebook.FacebookContentProvider" android:exported="true" />
登録時のキーハッシュ
keytool -exportcert -alias androiddebugkey -keystore ./app/irof_history_debug.keystore | openssl sha1 -binary | openssl base64
な感じで作成
自動生成系
下記は、ManifestMarger時にマージされて付与される
<provider android:authorities="${applicationId}.FacebookInitProvider" android:exported="false" android:name="com.facebook.internal.FacebookInitProvider"/>
TwitterKit(febric)
これは AndroidManifest.xml にべた書きしか駄目*2
- app/src/main/AndroidManifest.xml
<meta-data android:name="io.fabric.ApiKey" android:value="YOUR_API_KEY" />
- app/src/debug/AndroidManifest.xml
<meta-data tools:replace="android:value" android:name="io.fabric.ApiKey" android:value="YOUR_DEBUG_API_KEY" />
applicationとかの差し替えの場合は、tools:replace="android:name" となる
いつものお話ですね。。
独自ContentProvider の話
- app/AndroidManifest.xml
<provider android:name=".provider.DatabaseProvider" android:authorities="${applicationId}.DatabaseProvider" <!--◎--> android:exported="false" />
◎が端末ユニークである必要があるため、別々にしないと駄目
- libraryProject側に記載しても、MainP側で
- ManifestMargerで全 AndroidManifest.xmlがマージ
- ${applicationId}を置き換え
- placeHolderが適応
の流れなので、library-projectのパッケージが違う場合は期待通り動かない
- app/DatabaseContract.java
public class DatabaseContract { /** The authority for the database provider */ public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".DatabaseProvider"; // ... }
かプログラムで動的に取るか・・・*3
searchable
下記みたいな書き方が可能
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:searchSuggestAuthority="${applicationId}.hoge.fuga" //★ android:searchSuggestSelection=" ? " android:searchSuggestIntentAction="android.intent.action.SEARCH" android:label="@string/search_label" android:hint="@string/search_hint" android:searchMode="showSearchLabelAsBadge" android:imeOptions="actionSearch" android:inputType="textPersonName"/>
を参照
FileProvider
Uriを作成する仕組み(共有機能)
- files-path
- Context.getFilesDir()
- cache-path
- Context.getCacheDir()
- external-path
- Environment.getExternalStorageDirectory()
- SD権限は別途必要
- AndroidManifest.xml
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" //★ android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider>
類似の話
<sync-adapter android:accountType="${applicationId}" android:allowParallelSyncs="false" android:contentAuthority="${applicationId}.DatabaseProvider" android:isAlwaysSyncable="true" android:supportsUploading="true" android:userVisible="true" /> <account-authenticator android:accountType="${applicationId}" android:icon="@drawable/ic_launcher" android:label="@string/account_authenticator_label" android:smallIcon="@drawable/ic_launcher" />
adobe creative sdk(2018/03/01追記)
な話で話題になってる奴ですが、このFWの場合はaar内のAndroidManifest.xmlに
{appPackageName} というmanifestPlaceholdersを定義しましょう
という形式ですね。
で、Android 3.0 DSLベースで 試しててハマったのが
- app/build.gralde (NG)
android { defaultConfig { manifestPlaceholders = [appPackageName: "${applicationId}"] manifestPlaceholders = [appName: "@string/app_name"] //★この状態だとmanifestPlaceholdersのMap自体を再初期化する } }
- app/build.gralde (OK)
apply plugin: 'com.github.gfx.ribbonizer' android { defaultConfig { manifestPlaceholders = ['appPackageName': "${applicationId}"] manifestPlaceholders += ['appName': "@string/app_name"] // += である必要があり } flavorDimensions "debug" //◎ buildTypes{ release{ } debug{ } debug_hoge{ initWith(debug) matchingFallbacks["debug"] //◎ defaultConfig.manifestPlaceholders ['appPackageName'] ="${applicationId}.debug" defaultConfig.manifestPlaceholders ['appName']= "あいうえお" //固定文字列でもOK。ただ結合は無理 } } } ribbonizer { builder { variant, iconFile -> ant.echo "variant="+variant.buildType.name if (variant.buildType.name.indexOf("debug")!=-1) { if (variant.buildType.name == "debug_hoge") { // TODO: debug_hogeのときだけリボンをつける return greenRibbonFilter(variant, iconFile) } else{ return null //no effect ribonnizer } } } }
- ◎・・library projectを使っている場合指定しないとビルドが中止される
- キーの箇所をシングルで囲まないと代入上書きできない*4
- buildTypesの状態だとdefaultConfigの値はまだ初期化されてないのでベタ値を入れるしかない*5
- ribonnizer は return nullだとリボンつけない
AS3からgradle DSLに入った
— close_yutori (@kimukou2628) 2018年6月8日
flavor使ったときにデフォルトを指定すると言う奴なんだけど、作り悪くて
flavor使わんでもエラーになるから
flavorDimensions "debug"
と取りあえず書いとけ~なおまじないですね~(^^;;
正確には、
— close_yutori (@kimukou2628) 2018年6月8日
flavorのマッチングのデフォルトのBuildTypeを指定する
ですね。
一時期マッチング対象探せなくてGalaxtSyncがコケまくってたので。
で単一プロジェクトなら良いんだけどlibraryProject入れると再発。
あとmatchingFallbacks
も同じ対応ですね(前は探してたのですが止めた
- AS2.3自体は探してくれてたんですけどね・・。
- 高速化のために冗長な検索処理は削除されましたorz
- AS3.1ベースだと、compleの記述が残ってると高頻度でGradleSync失敗。
- これもチェックやめたんだろうなー*6
呼び出し側で気をつけること(2017/7/18追記)
- 従来通りで気にしないでいい書き方
Intent intent = new Intent(this,MainActivity.class); startActivity(intent);
- この書き方の場合は注意
Intent intent = new Intent(); intent.setClassName(getPackageName(), "hoge.fuga.maiu.MainActivity"); //★ startActivity(intent); //動かない書き方(1) intent.setClassName(getPackageName(), getPackageName() + ".MainActivity"); //動かない書き方(2) intent.setClassName("hoge.fuga.maiu","hoge.fuga.maiu.MainActivity");
という形になるから
で問題となることは・・・
buildTypesでで、debug版のパッケージ名にsuffix付けると、ActivityとかFragment作成したときのRが、suffix付きで生成されて必ずエラーになるの手間はそれほどないけど地味に嫌です…
— 赤兎馬 (@sekitoba) 2017年4月11日
ありがとうございます。AndroidStudioのbuildValiantsウィンドウで選択しているbuildTypeにsuffixなどが設定されている場合、こちらからRを生成しているようでした… pic.twitter.com/My9KONNVGY
— 赤兎馬 (@sekitoba) 2017年4月11日
正にこの現象。
- debugSuffix とかつけたり
- productFlavorつくったり
すると Rの生成がたまにおかしくなって Fragmentのレイアウト参照箇所のソースとかが定期的に真っ赤になる
cleanすれば治るんだけど、ビルドが不安定orz
だた、
とかあると、debugサフィックス を除去して、上記のファイルを除くとか正直面倒くさい><
併用すると便利なライブラリ
gradle-android-ribbonizer-plugin
debug=true
のbuildTypeのアイコンに、buildType名でリボンを付けてくれるgradle plugin*8
ribbonizerが使いづらい*9という場合は、manifestPlaceholders で頑張るって話は確かにあるなー。下記参照
Android-Iconics
下記に記載情報を移動、整理