1.項目結構
其中
target.apk爲目標apk,包名爲 com.zian.target
PermissionManager爲權限工具類
(權限以及安裝可以參考我另一篇博客 : https://blog.csdn.net/qq_30837235/article/details/83383230)
2.代碼
//權限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
import android.Manifest
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import kotlinx.android.synthetic.main.activity_main.*
import java.io.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.w("device", android.os.Build.BRAND)
btn_to_app.setOnClickListener {
toApp()
}
}
fun toApp() {
//如果已安裝 跳轉
if (checkAppInstalled(this, "com.zian.target")) {
val intent = packageManager.getLaunchIntentForPackage("com.zian.target")
if (intent != null) {
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
} else {
showInstallDialog()
}
}
/**
* 通過包名判斷是否已安裝該應用
* (可能有更好的解決方案)
*/
fun checkAppInstalled(context: Context, pkgName: String): Boolean {
val pm = context.packageManager
val infoList = pm.getInstalledPackages(0)
if (infoList == null) {
return false
} else {
for (packageBean in infoList) {
if (pkgName == packageBean.packageName) {
return true
}
}
}
return false
}
fun showInstallDialog() {
val builder = AlertDialog.Builder(this)
builder
.setMessage("安裝Target.Apk,是否繼續")
.setPositiveButton("安裝") { dialogInterface, i ->
dialogInterface.dismiss()
requestPermission()
}
.setNegativeButton("取消") { dialogInterface, i -> dialogInterface.dismiss() }
builder.setCancelable(false)
builder.show()
}
//文件寫入權限請求
fun requestPermission() {
PermissionManager.newBuilder(this)
.setPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.callBack(object : PermissionManager.PermissionRequestCallBack {
override fun successCallBack() {
prepareInstall(this@MainActivity)
}
override fun failureCallBack() {
showGetPermissionDialog(this@MainActivity)
}
})
}
fun showGetPermissionDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle("權限管理")
.setMessage("請開啓相應權限")
.setPositiveButton("前往") { dialogInterface, i ->
dialogInterface.dismiss()
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = Uri.parse("package:" + context.packageName)
context.startActivity(intent)
}
.setNegativeButton("取消") { dialogInterface, i -> dialogInterface.dismiss() }
builder.setCancelable(false)
builder.show()
}
//複製asset目錄下的apk文件並安裝
fun prepareInstall(context: Context) {
val assets = context.assets
try {
val stream = assets.open("target.apk")
if (stream == null) {
Log.e("error", "no file")
return
}
val folder = Environment.getExternalStorageDirectory()
.absolutePath + "/apk/"
val f = File(folder)
if (!f.exists()) {
f.mkdir()
}
val apkPath = Environment.getExternalStorageDirectory()
.absolutePath + "/apk/" + "target.apk"
val file = File(apkPath)
file.createNewFile()
writeStreamToFile(stream, file)
installApp(context, "com.zian.apptest", apkPath)
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun writeStreamToFile(stream: InputStream, file: File) {
try {
var output: OutputStream? = null
try {
output = FileOutputStream(file)
} catch (e1: FileNotFoundException) {
e1.printStackTrace()
}
try {
try {
val buffer = ByteArray(1024)
var read = 0
while (true) {
output!!.write(buffer, 0, read)
read = stream.read(buffer)
if (read <= 0) {
break
}
}
output!!.flush()
} finally {
output!!.close()
}
} catch (e: Exception) {
e.printStackTrace()
}
} finally {
try {
stream.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
fun installApp(context: Context, packageName: String, filePath: String) {
val appFile = File(filePath)
if (!appFile.parentFile.exists()) {
appFile.parentFile.mkdir()
}
//判斷版本是否在7.0以上
//跳轉到新版本應用安裝頁面
if (Build.VERSION.SDK_INT >= 24) {
//yourname 是定義在xxxx.xml中的值
val apkUri = FileProvider.getUriForFile(
context,
"$packageName.fileprovider",
appFile
)//在AndroidManifest中的android:authorities值
val install = Intent(Intent.ACTION_VIEW)
install.flags = Intent.FLAG_ACTIVITY_NEW_TASK
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
install.setDataAndType(apkUri, "application/vnd.android.package-archive")
context.startActivity(install)
} else {
val install = Intent(Intent.ACTION_VIEW)
install.setDataAndType(Uri.fromFile(appFile), "application/vnd.android.package-archive")
install.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(install)
}
System.exit(0)
}
}
3.我真無聊...居然寫這個...