두 가지 방법을 활용해서 Apk File 을 설치하는 동작을 구현 하려고 합니다.
첫 번째는 asset 으로부터 apk file 을 가져와서 설치하는 것과
두 번째는 SAF 에서 apk file 을 선택해서 설치하는 예제입니다.
1. 예제 다운로드
https://github.com/bictoselfdev/InstallApkEx
2. Apk 설치
(1) 권한 요청
Apk 설치를 위해 아래와 같이 두 가지 권한 요청이 필요합니다.
AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
MainActivity.kt
private fun requestPermission(activity: Activity) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!activity.packageManager.canRequestPackageInstalls()) {
val intent = Intent(
Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
Uri.parse("package:${activity.packageName}")
)
activity.startActivityForResult(intent, 100)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
(2) Apk 설치 요청
권한이 모두 준비되었고 Apk file 의 uri 정보를 알고 있다면,
아래 함수를 호출해서 Apk 설치가 가능합니다.
private fun installApkFile(activity: Activity, uri: Uri?) {
uri?.let {
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setDataAndType(it, "application/vnd.android.package-archive")
activity.startActivity(intent)
}
}
3. Apk File Uri 정보 가져오기
(1) assets
assets 에 미리 준비된 Apk file 을 내부 저장소에 저장합니다.
MainActivity.kt
private fun saveApkFileFromAssets() {
try {
val inputStream = assets.open("MyApplication.apk")
val outPath = filesDir.absolutePath + "/MyApplication.apk"
val outputStream = FileOutputStream(outPath)
while (true) {
val data = inputStream.read()
if (data == -1) break
outputStream.write(data)
}
inputStream.close()
outputStream.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
apk file 이 내부 저장소에 준비되었다면 provider 를 활용해서
apk file 의 uri 정보를 가져올 수 있습니다.
AndroidManifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:enabled="true"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider" />
</provider>
file_provider.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- 내부 저장소 -->
<files-path
name="files"
path="." />
</paths>
MainActivity.kt
private fun getUriByProvider(path: String): Uri? {
var uri: Uri? = null
try {
val file = File(path)
if (file.exists()) {
uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file)
}
} catch (e: Exception) {
e.printStackTrace()
}
return uri
}
(2) SAF 으로부터 Uri 정보 가져오기
준비된 apk file 이 아니라, 사용자가 직접 설치하고 싶은 apk file 을 선택하기 위해 SAF 를 활용합니다.
SAF 으로부터 선택된 apk file 의 uri 정보는 onActivityResult 에서 받을 수 있습니다.
MainActivity.kt
private fun openFileSAF(activity: Activity) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/vnd.android.package-archive"
}
activity.startActivityForResult(intent, requestCodeSAF)
}
MainActivity.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
when (requestCode) {
requestCodeSAF -> {
val uri = data?.data
uri?.let { installApkFile(this, it) }
}
}
}
}
[참고자료]
https://codechacha.com/ko/how-to-install-and-uninstall-app-in-android/
0 comments: