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 = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
File(context.filesDir, "apk")
} else {
File(context.getExternalFilesDir(""), "apk")
}
if (!folder.exists()) {
folder.mkdir()
}
val apkPath =folder.absolutePath + File.separator + "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 {
val fos = FileOutputStream(file)
val buffer = ByteArray(1024)
var len: Int
var total = 0
while ((stream.read(buffer).also { len = it }) != -1) {
fos.write(buffer, 0, len)
total += len
}
fos.flush()
fos.close()
stream.close()
} catch (e1: Exception) {
e1.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.我真无聊...居然写这个...