🍣

Mac で Android の apk ファイルを展開し、再構築する

2022/11/05に公開

はじめに

今回、既存の Android アプリの一部のみを編集して再インストールしたかったのでその手順をメモします。

筆者のやりたいことは UBhind というアプリの AndroidManifest.xml を編集することです。
最終的に Android 端末へのインストールには成功しましたが、アプリの起動には失敗しています。厳密にはアプリ自体は立ち上がるのですが白い画面のまま進みません。裏側の通信に失敗しているか、署名周りの検証に失敗していると思われます。

上記の通り本来やりたいことは達成できていませんが、Android の apk ファイルの展開、再構築自体には成功していそうなため、記事にまとめます。
筆者は普段はバックエンド領域で開発しており、Android は初心者です。もし間違いがありましたら指摘をお願いします。

また、本記事はほぼ「Apktoolを使ってapkファイルの展開、再構築をする」の焼き直しです。
現時点では Mac でもこの手順で行けそうです。

必要なもの

  1. JDK7 (Android Sutdio を install で付随)
  2. Android SDK (Android Sutdio を install で付随)
  3. apktool (brew で install 可)
  4. apktool_XXX.jar (最新のものを DL)
  5. 使用するAndroid端末のframework-res.apk
  6. 展開、再構築したいapkファイル

4, 5, 6 の 3つ は同一ディレクトリ内に配置すればOKです。

apktool_XXX.jar の用意

apktool のリポジトリ から最新のバージョンを DL しましょう。

XXX の箇所は version になります。 DL 後は apktool.jar にリネームしましょう。

❯ mv apktool_2.6.1.jar apktool.jar

frameword-res.apk の用意

Android SDK を install していること、Mac と Android 端末が USB で接続されていることが前提で説明します。
次のコマンドでダウンロードすることができます。

❯ adb pull /system/framework/framework-res.apk

ここからエラーログとその対処法も載せておきます。

failed to get feature set: device unauthorized. というエラーメッセージが表示された場合、対処法は2つあります。

  1. adb kill-server を実行して再試行
  2. Android 端末に表示されている許可ダイアログでOKを選択

2 は初回 pull 時に発生します。PC から Android 端末へのアクセスを許可する必要があります。

❯ adb pull /system/framework/framework-res.apk
adb: error: failed to get feature set: device unauthorized.
This adb server's $ADB_VENDOR_KEYS is not set
Try 'adb kill-server' if that seems wrong.
Otherwise check for a confirmation dialog on your device.

❯ adb kill-server

これらを解消すると Android 端末のファイルを adb 経由で取得することができます。

❯ adb pull /system/framework/framework-res.apk
/system/framework/framework-res.apk: 1 file pulled, 0 skipped. 35.9 MB/s (59380800 bytes in 1.578s)ls
framework-res.apk

展開、再構築したい apk ファイルの用意

今回は対象の Android 端末から既にインストールされている apk ファイルを取得する手順を説明します。

  1. パソコンのadb環境を用意する
  2. 対象アプリのパッケージ名を調べる
  3. 対象アプリの保存先(パス)を調べる
  4. 対象アプリのapkを抽出する(adb pull)

Android Studio を install していれば adb 環境は構築されているはずなので、この手順は省略します。

まずは対象アプリのパッケージ名を調べる必要があります。

パッケージ名さえわかればOKですが、今回は Aplin というアプリを使用しました。このアプリを開くと一覧画面にてアプリ名とパッケージ名を確認することができます。

筆者の場合に取得したいアプリである UBhind では、パッケージ名は kr.co.rinasoft.howuse でした。

次にアプリのパスを調べます。

adb の list packages コマンドでパッケージの一覧を取得することが可能です。その結果を調べたパッケージ名で grep します。

絞り込み結果の /data/app/~~ ~ ==/base.apk までがパスになります。
下記の UBnihd の例では /data/app/~~FF-_CnRP-BOzwo30A1Tn1Q==/kr.co.rinasoft.howuse-yImUIjxyHIYBi-uhoIroTw==/base.apk がパスになります。

❯ adb shell pm list packages -f | grep kr.co.rinasoft.howuse
package:/data/app/~~FF-_CnRP-BOzwo30A1Tn1Q==/kr.co.rinasoft.howuse-yImUIjxyHIYBi-uhoIroTw==/base.apk=kr.co.rinasoft.howuse

最後に対象アプリの apk ファイルを取得します。

Android 端末から adb pull します。このとき、ファイル名は base.apk になります。わかり易い名前に リネームしましょう。

❯ adb pull /data/app/~~FF-_CnRP-BOzwo30A1Tn1Q==/kr.co.rinasoft.howuse-yImUIjxyHIYBi-uhoIroTw==/base.apk                      
/data/app/~~FF-_CnRP-BOzwo30A1Tn1Q==/kr.co.rinasoft.howuse-yImUIjxyHIYBi-uhoI...Tw==/base.apk: 1 file pulled, 0 skipped. 37.0 MB/s (16963889 bytes in 0.437s)ls
base.apk

❯ mv base.apk UBhind.apk

手順

いよいよ apk ファイルを展開、再構築します。手順は次のとおりです。

  1. 必要なツールの配置
  2. apk ファイルの展開
  3. apk ファイルの編集
  4. apk ファイルの構築
  5. apk ファイルを Android 端末へ install

必要なツールの配置

次の 3つ を同一ディレクトリ内に配置します。

  1. 展開したい apk ファイル
  2. apktool.jar
  3. framework-res.apk
ls
UBhind.apk apktool.jar framework-res.apk

apk ファイルの展開

apk ファイルを展開します。

展開には apktool d コマンドを使用します。
実行するとカレントディレクトリ内に apk ファイルと同名のディレクトリが作成され、その中に展開後のファイルが配置されます。

❯ apktool d UBhind.apk
実際の実行ログを残しておきます。

UBhind というディレクトリが作成されていることがわかります。

❯ apktool d UBhind.apk
I: Using Apktool 2.6.1 on UBhind.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/xxx/Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Baksmaling classes2.dex...
I: Baksmaling classes3.dex...
I: Baksmaling classes4.dex...
I: Baksmaling assets/audience_network.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
I: Copying META-INF/services directory

❯ ls
UBhind UBhind.apk apktool.jar framework-res.apk

apk ファイルの編集

apk ファイルが展開されたので、内容を自由に編集します。何もかもが自由の無法地帯です。恐ろしいですね。

筆者の場合は AndroidManifest.xml を編集しました。おそらくこれが原因で Android 端末でのアプリ立ち上げには失敗しています。南無三。

apk ファイルの構築

apk ファイルを再構築します。

再構築には apktool b コマンドを使用します。
構築元のディレクトリとビルド後のファイル名を指定します。

❯ apktool b -c UBhind -o newUBhind.apk
こちらも実行ログを残しておきます

実行すると、.apk ファイルと .apk.apktool_temp ファイルの 2つ が作成されることがわかります。

❯ apktool b -c UBhind -o newUBhind.apk
-c/--copy-original has been deprecated. Removal planned for v3.0.0 (#2129)
I: Using Apktool 2.6.1
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether sources has changed...
I: Smaling smali_assets folder into assets.dex...
I: Checking whether sources has changed...
I: Smaling smali_classes3 folder into classes3.dex...
I: Checking whether sources has changed...
I: Smaling smali_classes4 folder into classes4.dex...
I: Checking whether sources has changed...
I: Smaling smali_classes2 folder into classes2.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Copying libs... (/kotlin)
I: Copying libs... (/META-INF/services)
I: Copy original files...
I: Copy AndroidManifest.xml...
I: Copy stamp-cert-sha256...
I: Copy META-INF...
I: Building apk file...
I: Copying unknown files/dir...
java.util.zip.ZipException: duplicate entry: stamp-cert-sha256

❯ ls
UBhind UBhind.apk apktool.jar framework-res.apk
newUBhind.apk newUBhind.apk.apktool_temp

apk ファイルを Android 端末へ install

apk ファイルを端末へ install します。

❯ adb install newUBhind.apk 

筆者の環境では次の2つのエラーが発生しました。
これらを解消した後に、 adb install に成功しました。

INSTALL_PARSE_FAILED_NO_CERTIFICATES エラー

INSTALL_PARSE_FAILED_NO_CERTIFICATES というエラーが発生しました。おそらく AndroidManifest.xml を編集している影響かと思われます。

❯ adb install newUBhind.apk 
Performing Streamed Install
adb: failed to install newUBhind.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Failed to collect certificates from /data/app/vmdl566247472.tmp/base.apk: File res/drawable-xhdpi-v4/ico_app.png in manifest does not exist]

色々と試した結果、 apk ファイルを再署名することで apk ファイルの install に成功しました。

署名には apksigner というツールを使用します。手順は以下です。

  1. 署名キーの作成
  2. apksigner のパスを探す
  3. apksigner で署名

署名キーの作成には keytool コマンドを使用します。
キーの作成時にパスワードをセットします。このパスワードは 3 の署名時に必要になります。

apksigner のパスは筆者の場合は ~/Library/Android/sdk/build-tools/${version}/apksigner にありました。バージョンは適当なものでOKです。

❯ keytool -genkey -v -keystore test.keystore -alias TEST -keyalg RSA -validity 10000

❯ ~/Library/Android/sdk/build-tools/32.0.0/apksigner sign --ks test.keystore -v --v2-signing-enabled true --ks-key-alias TEST newUBhind.apk

これにて本エラーは解決できるはずです。

INSTALL_FAILED_UPDATE_INCOMPATIBLE エラー

また、 INSTALL_FAILED_UPDATE_INCOMPATIBLE というエラーが発生するケースがあります。

これは同じパッケージ名のアプリがすでに存在することが原因です。Android 端末の同名パッケージのアプリをアンインストールしましょう。
筆者の場合は元々 Android 端末にあるアプリを編集し再インストールしようとしているため、このエラーが発生しました。

アプリのアンインストールには adb uninstall コマンドを使用します。

❯ adb uninstall kr.co.rinasoft.howuse

このあと再度インストールしてみましょう。

終わりに

慣れない Android に四苦八苦しながら、それでもやりたいことのために楽しく進めることができました。
こちらの記事がどなたかのお役に立てましたら幸いです。

参考文献

Discussion