问题描述
我注意到PackageManager上有一个名为" getPackageInstaller ".
I've noticed there is a new function on the PackageManager called "getPackageInstaller" , with minAPI 21 (Lollipop).
我已经到达" PackageInstaller "类,这就是它的内容:
I've reached the "PackageInstaller" class, and this is what it is written about it:
已通过以下方式交付了要安装的应用程序 PackageInstaller.Session,任何应用程序都可以创建.一旦会议 创建后,安装程序可以将一个或多个APK流式传输到位,直到 它决定提交或销毁会话.承诺可能 需要用户干预才能完成安装.
An app is delivered for installation through a PackageInstaller.Session, which any app can create. Once the session is created, the installer can stream one or more APKs into place until it decides to either commit or destroy the session. Committing may require user intervention to complete the installation.
会话可以安装全新的应用程序,升级现有应用程序或添加新的应用程序 拆分为现有应用.
Sessions can install brand new apps, upgrade existing apps, or add new splits into an existing app.
问题
- 该课程用于做什么?它甚至可用于第三方应用程序(我对此没有提及)?
- 它真的可以安装应用程序吗?
- 它在后台执行吗?
- 有哪些限制?
- 需要权限吗?如果是这样,哪个?
- 有没有使用方法的教程?
推荐答案
好的,我找到了一些答案:
OK, I've found some answers:
- 可用于安装/更新APK文件(包括拆分APK文件).甚至更多.
- 是的,但用户需要先确认一个应用,再确认一个应用.
- 也许该应用是内置的.
- 似乎需要在请求用户安装之前读取整个APK文件.
- 需要权限 REQUEST_INSTALL_PACKAGES
- 还没有找到任何东西,但是有人在这里向我展示了如何安装split-apk文件,这是使用SAF(带有和不带有PackageInstaller)对单个文件进行安装的方法.请注意,这只是一个示例.我认为在UI线程上完成所有操作不是一个好习惯.
清单
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
package="com.android.apkinstalltest">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<application tools:ignore="AllowBackup,GoogleAppIndexingWarning"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".APKInstallService"/>
</application>
</manifest>
APKInstallService
class APKInstallService : Service() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
Log.d("AppLog", "Requesting user confirmation for installation")
val confirmationIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
confirmationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
startActivity(confirmationIntent)
} catch (e: Exception) {
}
}
PackageInstaller.STATUS_SUCCESS -> Log.d("AppLog", "Installation succeed")
else -> Log.d("AppLog", "Installation failed")
}
stopSelf()
return START_NOT_STICKY
}
override fun onBind(intent: Intent) = null
}
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var packageInstaller: PackageInstaller
@TargetApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
packageInstaller = packageManager.packageInstaller
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "application/vnd.android.package-archive"
startActivityForResult(intent, 1)
}
// override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
// super.onActivityResult(requestCode, resultCode, resultData)
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && requestCode == 1 && resultCode == Activity.RESULT_OK && resultData != null) {
// val uri = resultData.data
// grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
// val intent = Intent(Intent.ACTION_INSTALL_PACKAGE)//
// .setDataAndType(uri, "application/vnd.android.package-archive")
// .putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
// .putExtra(Intent.EXTRA_RETURN_RESULT, false)
// .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
// startActivity(intent)
// }
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && requestCode == 1 && resultCode == Activity.RESULT_OK && resultData != null) {
val uri = resultData.data ?: return
grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
val installParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
var cursor: Cursor? = null
var outputStream: OutputStream? = null
var inputStream: InputStream? = null
var session: PackageInstaller.Session? = null
try {
cursor = contentResolver.query(uri, null, null, null, null)
if (cursor != null) {
cursor.moveToNext()
val fileSize = cursor.getLong(cursor.getColumnIndex(DocumentsContract.Document.COLUMN_SIZE))
val fileName = cursor.getString(cursor.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME))
installParams.setSize(fileSize)
cursor.close()
val sessionId = packageInstaller.createSession(installParams)
Log.d("AppLog", "Success: created install session [$sessionId] for file $fileName")
session = packageInstaller.openSession(sessionId)
outputStream = session.openWrite(System.currentTimeMillis().toString(), 0, fileSize)
inputStream = contentResolver.openInputStream(uri)
inputStream.copyTo(outputStream)
session.fsync(outputStream)
outputStream.close()
outputStream = null
inputStream.close()
inputStream = null
Log.d("AppLog", "Success: streamed $fileSize bytes")
val callbackIntent = Intent(applicationContext, APKInstallService::class.java)
val pendingIntent = PendingIntent.getService(applicationContext, 0, callbackIntent, 0)
session!!.commit(pendingIntent.intentSender)
session.close()
session = null
Log.d("AppLog", "install request sent. sessions:" + packageInstaller.mySessions)
}
} catch (e: Exception) {
Log.d("AppLog", "error:$e")
} finally {
outputStream?.close()
inputStream?.close()
session?.close()
cursor?.close()
}
}
}
}
这篇关于什么是"PackageInstaller"?棒棒糖上课,如何使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!