APKからAndroidアプリを更新する実装

Intentを用いた(半)自動更新。
主な用途はGooglePlayを経由しない社内アプリなど。



Intent経由でインストーラ呼び出し




Intent経由でインストーラを呼び出せるのでこれを利用する。


// ファイルパス
val file: File = File(getExternalFilesDir(""), "test.apk")

// ファイルのURI
val uri: Uri = FileProvider.getUriForFile(
    applicationContext,
    BuildConfig.APPLICATION_ID + ".provider",
    file
)
// インストーラ呼び出し
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
intent.flags =
    Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
startActivity(intent)


基本的にデータタイプapplication/vnd.android.package-archiveへファイルのUriを渡してフラグに読み書き権限を付与すれば良い。
Intentに渡すファイルUriはFileProvider.getUriForFileを使用するがAndroid7以降からファイルアクセスの制限がキツくなったためアクセス許可が必要になる。



FileProviderを利用して一時的にアクセス許可をおこなう


FileProviderとはURI経由でアプリ間のファイルアクセスの許可をおこなう仕組み。
インストーラからAPKをインストールするにはAPKへアクセスできるようにする必要がある。

AndroidManifest.xml

application内に以下を追記。

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_path" />
</provider>

android:authoritiesはFileProvider.getUriForFileの第2引数と一致させること。
android:resourceのみ変更可能(↓で作成するファイル名を指定する)

app/src/main/res/xml/provider_path.xml


アクセス許可するディレクトリを指定する。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="name" path="./" />
</paths>

対象ディレクトリは大きく6種類。
https://developer.android.com/reference/androidx/core/content/FileProvider?hl=ja

files-path

Context.getFilesDir()で指定されるディレクトリ

cache-path

getCacheDir()で指定されるディレクトリ

external-path

外部ストレージのルートディレクトリ
Environment.getExternalStorageDirectory()で指定される。

external-files-path

外部ストレージのアプリのルートディレクトリ。
Context.getExternalFilesDir(null)で指定される。
具体的には
ログ出力した場合 /storage/emulated/0/Android/data/パッケージ名/files
Device File Explorerから確認した場合 /sdcard/Android/data/パッケージ名/files/
となる。
今回はこれを使用する。
外部雨ストレージの詳細については以下にまとめている
https://trueman-developer.blogspot.com/2022/09/android10kotlin.html

external-cache-path


外部ストレージのアプリのキャッシュディレクトリ。
Context.getExternalCacheDir()で指定される。
アプリ更新目的なら一時領域のこちらを使用する方が良いかもしれない。

external-media-path

アプリの外部メディア領域のルートディレクトリ。
Context.getExternalCacheDir()で指定される。
API21以降のみ。

nameは任意。
pathはサブディレクトリ名を指定する。ルート直下の場合は"./"を指定する。

以上でアプリアップデートの仕組みは実装可能。
初回のみ「この提供元のアプリを許可」を手動でオンにする必要がある。




参考


https://developer.android.com/reference/kotlin/androidx/core/content/FileProvider
https://developer.android.com/training/secure-file-sharing/setup-sharing?hl=ja
http://enjoy-rfid.blogspot.com/2019/03/google-playandroid.html
https://azunobu.hatenablog.com/entry/2019/06/27/120908
https://www.ninton.co.jp/archives/2745

2022年10月24日月曜日