本文介绍了什么是"PackageInstaller"?棒棒糖上课,如何使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到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.

问题

  1. 该课程用于做什么?它甚至可用于第三方应用程序(我对此没有提及)?
  2. 它真的可以安装应用程序吗?
  3. 它在后台执行吗?
  4. 有哪些限制?
  5. 需要权限吗?如果是这样,哪个?
  6. 有没有使用方法的教程?

推荐答案

好的,我找到了一些答案:

OK, I've found some answers:

  1. 可用于安装/更新APK文件(包括拆分APK文件).甚至更多.
  2. 是的,但用户需要先确认一个应用,再确认一个应用.
  3. 也许该应用是内置的.
  4. 似乎需要在请求用户安装之前读取整个APK文件.
  5. 需要权限 REQUEST_INSTALL_PACKAGES
  6. 还没有找到任何东西,但是有人在这里向我展示了如何安装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"?棒棒糖上课,如何使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-18 11:16