Android 10 - 找不到处理 Intent 的 Activity
Posted
技术标签:
【中文标题】Android 10 - 找不到处理 Intent 的 Activity【英文标题】:Android 10 - No Activity found to handle Intent 【发布时间】:2020-01-24 21:48:13 【问题描述】:我的第 3 方应用程序可以让最终用户从我们的服务器下载更新的 APK,然后该应用程序将在下载完成后调用该 APK 上的安装包管理器。同样的方法适用于所有版本的 android 操作系统,但现在它会在 Android 10 (api 29) 上崩溃。我还没有看到任何人有类似的问题,任何帮助将不胜感激!
这是我用来从我的应用程序中调用 APK 文件的方法:
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 上:
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)
【问题讨论】:
您是否在服务中运行此代码?会不会和developer.android.com/guide/components/activities/…有关? 巧合的是,它是从服务中运行的,但是即使直接从 mainactivity 运行相同的代码,甚至在服务中使用 mainactivity 的实例时,我也会得到完全相同的异常 嗯。因此,大概没有可用于处理意图的活动。什么活动通常会在早期版本的 Android 上响应? 它的行为通常与您在文件资源管理器中单击 APK 文件相同,它会显示安装此 APK 或取消的选项 【参考方案1】:ACTION_VIEW
(适用于 APK)和 ACTION_INSTALL_PACKAGE
在 Android 10 中已弃用。您需要切换到 PackageInstaller
API。
This sample app 演示了安装简单 APK 的基础知识。胆子在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(application, 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(application, InstallReceiver::class.java)
val pi = PendingIntent.getBroadcast(
application,
PI_INSTALL,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
session.commit(pi.intentSender)
session.close()
当一个activity或fragment调用install()
,提供一个Uri
给APK,我使用PackageInstaller
来安装它:
PackageManager
获取PackageInstaller
创建一个SessionParams
并从中打开一个会话
将 APK 的字节(从 Uri
中的 InputStream
读取)写入该会话提供的 OutputStream
致电commit()
实际开始安装过程,结果将通过PendingIntent
发送回应用程序
致电close()
关闭会话
API 很笨重,但它旨在处理广泛的场景,包括“App Bundle”风格的多 APK 安装。
【讨论】:
我自己回来回答这个问题,因为我找到了答案并在交叉引用 Google 的 APIDemos 时实施了修复,答案与您的完全相同,所以我接受了答案,但是Kotlin 示例让我畏缩:(我只对 Java 感兴趣,很高兴找到 Google 用 Java 编写的示例:android.googlesource.com/platform/development/+/master/samples/… 如果启动了带有操作Intent.ACTION_INSTALL_PACKAGE
的意图,是否有任何方法可以显示旧的更新/安装流程?我的观点是,使用 PackageInstaller 不会向用户显示安装更新进度,而是会在不通知用户的情况下静默更新并关闭应用程序。
@mathew11:AFAIK,您将负责该 UI。见developer.android.com/reference/kotlin/android/content/pm/…
@CommonsWare 有必要发送广播吗? val intent = Intent(getApplication(), InstallReceiver::class.java) val pi = PendingIntent.getBroadcast( getApplication(), PI_INSTALL, intent, PendingIntent.FLAG_UPDATE_CURRENT) session.commit(pi.intentSender)
我在哪里可以找到官方文档,他们说 ACTION_VIEW 已被 apk 弃用?以上是关于Android 10 - 找不到处理 Intent 的 Activity的主要内容,如果未能解决你的问题,请参考以下文章
解组 Android Intent Parcelable 时找不到类