自动更新应用程序而无需用户交互面临问题==>权限拒绝:不允许发送广播android.intent.action.PACKAGE_ADDED
Update APP automatically without user interaction facing issue==> Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED
我想在没有用户交互的情况下在有新版本可用时自动更新应用程序,假设有新版本可用并且下载到 [=45= 中的 Downloads 目录].
我遵循了以下示例。
Java Sample:
Kotlin Sample: https://www.sisik.eu/blog/android/dev-admin/update-app
面临这个异常
system_process W/ActivityManager: Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED from pid=-1, uid=10191
system_process W/ActivityManager: Unable to send startActivity intent
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED from pid=-1, uid=10191
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:21323)
at com.android.server.am.ActivityManagerService.broadcastIntentInPackage(ActivityManagerService.java:21974)
at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:372)
at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:245)
at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:8446)
at android.content.IntentSender.sendIntent(IntentSender.java:191)
at android.content.IntentSender.sendIntent(IntentSender.java:155)
at com.android.server.pm.PackageInstallerService$PackageInstallObserverAdapter.onUserActionRequired(PackageInstallerService.java:888)
at android.app.PackageInstallObserver.onUserActionRequired(PackageInstallObserver.java:28)
at com.android.server.pm.PackageInstallerSession.commitLocked(PackageInstallerSession.java:951)
at com.android.server.pm.PackageInstallerSession.access0(PackageInstallerSession.java:120)
at com.android.server.pm.PackageInstallerSession.handleMessage(PackageInstallerSession.java:294)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
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/Theme.AutoUpdateAppPractice"
android:usesCleartextTraffic="true">
<receiver
android:name="UpdateReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
CustomPackageInstaller.java
package com.odine.autoupdateapppractice;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class CustomPackageInstaller {
public static void installPackage(Context context, String installSessionId, String packageName, InputStream apkStream) {
PackageManager packageManger = context.getPackageManager();
PackageInstaller packageInstaller = packageManger.getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
PackageInstaller.Session session = null;
try {
Log.e(TAG, "installPackage: try");
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite(installSessionId, 0, -1);
byte buffer[] = new byte[1024];
int length;
int count = 0;
while ((length = apkStream.read(buffer)) != -1) {
out.write(buffer, 0, length);
count += length;
}
session.fsync(out);
out.close();
Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED);
session.commit(PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_UPDATE_CURRENT).getIntentSender());
} catch (Exception ex) {
Log.e(TAG, "installPackage: catch");
ex.printStackTrace();
} finally {
Log.e(TAG, "installPackage: finally");
if (session != null) {
session.close();
}
}
}
}
在我的 MainActivity.java 里面点击按钮调用 CustomPackageInstaller.installPackage() 写在上面 class
File file= new File(filePath);
InputStream targetStream = new FileInputStream(file);
CustomPackageInstaller.installPackage(
MainActivity.this,
"2",
"com.odine.autoupdateapppractice",
targetStream);
您收到的错误消息几乎可以告诉您问题出在哪里。您已请求软件包安装程序通过发送带有 ACTION = android.intent.action.PACKAGE_ADDED
的广播 Intent
来通知您完成。此广播Intent
只能由Android框架发送。普通应用无法发送此广播 Intent
.
您应该使用明确的 Intent
,在其中为此目的指定组件(程序包名称和 class 名称)。为此,您可以让软件包安装程序启动 Activity
或 BroadcastReceiver
。
注意:您的应用必须是设备所有者才能在没有用户交互的情况下执行此操作。
我想在没有用户交互的情况下在有新版本可用时自动更新应用程序,假设有新版本可用并且下载到 [=45= 中的 Downloads 目录].
我遵循了以下示例。
Java Sample:
Kotlin Sample: https://www.sisik.eu/blog/android/dev-admin/update-app
面临这个异常
system_process W/ActivityManager: Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED from pid=-1, uid=10191
system_process W/ActivityManager: Unable to send startActivity intent
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.PACKAGE_ADDED from pid=-1, uid=10191
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:21323)
at com.android.server.am.ActivityManagerService.broadcastIntentInPackage(ActivityManagerService.java:21974)
at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:372)
at com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:245)
at com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:8446)
at android.content.IntentSender.sendIntent(IntentSender.java:191)
at android.content.IntentSender.sendIntent(IntentSender.java:155)
at com.android.server.pm.PackageInstallerService$PackageInstallObserverAdapter.onUserActionRequired(PackageInstallerService.java:888)
at android.app.PackageInstallObserver.onUserActionRequired(PackageInstallObserver.java:28)
at com.android.server.pm.PackageInstallerSession.commitLocked(PackageInstallerSession.java:951)
at com.android.server.pm.PackageInstallerSession.access0(PackageInstallerSession.java:120)
at com.android.server.pm.PackageInstallerSession.handleMessage(PackageInstallerSession.java:294)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
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/Theme.AutoUpdateAppPractice"
android:usesCleartextTraffic="true">
<receiver
android:name="UpdateReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
CustomPackageInstaller.java
package com.odine.autoupdateapppractice;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class CustomPackageInstaller {
public static void installPackage(Context context, String installSessionId, String packageName, InputStream apkStream) {
PackageManager packageManger = context.getPackageManager();
PackageInstaller packageInstaller = packageManger.getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
PackageInstaller.Session session = null;
try {
Log.e(TAG, "installPackage: try");
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite(installSessionId, 0, -1);
byte buffer[] = new byte[1024];
int length;
int count = 0;
while ((length = apkStream.read(buffer)) != -1) {
out.write(buffer, 0, length);
count += length;
}
session.fsync(out);
out.close();
Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED);
session.commit(PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_UPDATE_CURRENT).getIntentSender());
} catch (Exception ex) {
Log.e(TAG, "installPackage: catch");
ex.printStackTrace();
} finally {
Log.e(TAG, "installPackage: finally");
if (session != null) {
session.close();
}
}
}
}
在我的 MainActivity.java 里面点击按钮调用 CustomPackageInstaller.installPackage() 写在上面 class
File file= new File(filePath);
InputStream targetStream = new FileInputStream(file);
CustomPackageInstaller.installPackage(
MainActivity.this,
"2",
"com.odine.autoupdateapppractice",
targetStream);
您收到的错误消息几乎可以告诉您问题出在哪里。您已请求软件包安装程序通过发送带有 ACTION = android.intent.action.PACKAGE_ADDED
的广播 Intent
来通知您完成。此广播Intent
只能由Android框架发送。普通应用无法发送此广播 Intent
.
您应该使用明确的 Intent
,在其中为此目的指定组件(程序包名称和 class 名称)。为此,您可以让软件包安装程序启动 Activity
或 BroadcastReceiver
。
注意:您的应用必须是设备所有者才能在没有用户交互的情况下执行此操作。