Android 10-未找到可处理意图的活动 [英] Android 10 - No Activity found to handle Intent

查看:110
本文介绍了Android 10-未找到可处理意图的活动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的第三方应用程序为最终用户提供了一种从我们的服务器下载更新的APK的方法,然后该应用程序将在下载完成后在该APK上调用安装包管理器.相同的方法适用于所有版本的Android OS,但现在它将在Android 10(api 29)上崩溃.我还没有看到遇到类似问题的任何人,我们将不胜感激!

My 3rd party app has a way for the end-user to download an updated APK from our server and then the app will invoke the install package manager on that APK after it's done downloading. This same method has worked for all versions of Android OS but now it will crash on Android 10 (api 29). I haven't seen anyone with a similar problem yet, any help would be greatly appreciated!

这是我用来从我的应用程序中调用APK文件的内容:

Here's what I use to call the APK file from within my app:

Intent intent = new Intent(Intent.ACTION_VIEW);
final File apkFile = new File(Files.getApkFileName());
Log.v("dt.update", "Start update from " + apkFile.getAbsolutePath());
intent.setDataAndType(Uri.fromFile(apkFile), application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

这是每次仅在Android 10/API29上都会返回的堆栈跟踪:

And here is the stacktrace coming back every time, only on Android 10 / API29:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.MyAppHere, PID: 11107
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/updatedapp.apk typ=application/vnd.android.package-archive flg=0x10000000 }
    at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2051)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1709)
    at android.app.Activity.startActivityForResult(Activity.java:5192)
    at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)
    at android.app.Activity.startActivityForResult(Activity.java:5150)
    at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:663)
    at android.app.Activity.startActivity(Activity.java:5521)
    at android.app.Activity.startActivity(Activity.java:5489)
    at android.view.View.performClick(View.java:7140)
    at android.view.View.performClickInternal(View.java:7117)
    at android.view.View.access$3500(View.java:801)
    at android.view.View$PerformClick.run(View.java:27351)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7356)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

推荐答案

ACTION_VIEW(适用于APK)和ACTION_INSTALL_PACKAGE在Android 10中已弃用.您需要切换到PackageInstaller API.

ACTION_VIEW (for APKs) and ACTION_INSTALL_PACKAGE were deprecated in Android 10. You need to switch to the PackageInstaller API.

此示例应用演示了获取安装了一个简单的APK.胆量在MainMotor:

This sample app demonstrates the basics for getting a simple APK installed. The guts are in the MainMotor:

/*
  Copyright (c) 2019 CommonsWare, LLC

  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain   a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
  by applicable law or agreed to in writing, software distributed under the
  License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS
  OF ANY KIND, either express or implied. See the License for the specific
  language governing permissions and limitations under the License.

  Covered in detail in the book _Elements of Android Q

  https://commonsware.com/AndroidQ
*/

package com.commonsware.q.appinstaller

import android.app.Application
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageInstaller
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

private const val NAME = "mostly-unused"
private const val PI_INSTALL = 3439

class MainMotor(app: Application) : AndroidViewModel(app) {
  private val installer = app.packageManager.packageInstaller
  private val resolver = app.contentResolver

  fun install(apkUri: Uri) {
    viewModelScope.launch(Dispatchers.Main) {
      installCoroutine(apkUri)
    }
  }

  private suspend fun installCoroutine(apkUri: Uri) =
    withContext(Dispatchers.IO) {
      resolver.openInputStream(apkUri)?.use { apkStream ->
        val length =
          DocumentFile.fromSingleUri(getApplication(), apkUri)?.length() ?: -1
        val params =
          PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
        val sessionId = installer.createSession(params)
        val session = installer.openSession(sessionId)

        session.openWrite(NAME, 0, length).use { sessionStream ->
          apkStream.copyTo(sessionStream)
          session.fsync(sessionStream)
        }

        val intent = Intent(getApplication(), InstallReceiver::class.java)
        val pi = PendingIntent.getBroadcast(
          getApplication(),
          PI_INSTALL,
          intent,
          PendingIntent.FLAG_UPDATE_CURRENT
        )

        session.commit(pi.intentSender)
        session.close()
      }
    }
}

当活动或片段调用install()并向APK提供Uri时,我使用PackageInstaller进行安装:

When an activity or fragment calls install(), supplying a Uri to the APK, I use PackageInstaller to install it:

  • PackageManager
  • 获取PackageInstaller
  • 创建一个SessionParams并从中打开一个会话
  • 将APK的字节(从InputStreamUri读取)写入该会话提供的OutputStream
  • 调用commit()实际开始安装过程,结果通过PendingIntent
  • 传递回应用程序
  • 致电close()关闭会话
  • Get a PackageInstaller from PackageManager
  • Create a SessionParams and open a session from it
  • Write the bytes of the APK (read from an InputStream from the Uri) to an OutputStream supplied by that session
  • Call commit() to actually begin the installation process, with results being delivered back to the app via a PendingIntent
  • Call close() to close up the session

该API笨拙,但旨在处理各种情况,包括"App Bundle"式的多APK安装.

The API is clunky, but it is designed to handle a wide range of scenarios, including "App Bundle"-style multi-APK installations.

这篇关于Android 10-未找到可处理意图的活动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆