自动更新APP,无需用户交互问题==> Permission Denial: not allowed to send broadcast android.intent.action.PACKAG

Posted

技术标签:

【中文标题】自动更新APP,无需用户交互问题==> Permission Denial: not allowed to send broadcast 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 【发布时间】:2021-08-07 17:24:48 【问题描述】:

我想在没有用户交互的情况下,当有新版本可用时自动更新APP,假设有新版本可用并下载到android中的Downloads目录。

我按照下面的例子。

Java 示例: https://***.com/a/51705614

Kotlin 示例: 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$1.onUserActionRequired(PackageInstallObserver.java:28)
        at com.android.server.pm.PackageInstallerSession.commitLocked(PackageInstallerSession.java:951)
        at com.android.server.pm.PackageInstallerSession.access$200(PackageInstallerSession.java:120)
        at com.android.server.pm.PackageInstallerSession$3.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() 写在上面的类中

 File file= new File(filePath);
 InputStream targetStream = new FileInputStream(file);

 CustomPackageInstaller.installPackage(
                MainActivity.this,
                "2",
                "com.odine.autoupdateapppractice",
                targetStream);

【问题讨论】:

【参考方案1】:

您收到的错误消息几乎可以告诉您问题所在。您已请求软件包安装程序在完成时通过发送广播 Intent 并使用 ACTION = android.intent.action.PACKAGE_ADDED 通知您。这个广播Intent只能由Android框架发送。普通应用无法发送此广播Intent

您应该使用显式的Intent,并为此指定组件(包名和类名)。为此,您可以让软件包安装程序启动 ActivityBroadcastReceiver


注意:您的应用必须是设备所有者才能在没有用户交互的情况下执行此操作。

【讨论】:

感谢您的回答,我明白了您的意思,假设如果我这样做Intent intent = new Intent(context, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); session.commit(PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_UPDATE_CURRENT).getIntentSender());,它不会更新我的应用程序并且日志中没有错误。 您需要使用PendingIntent.getActivity() 而不是PendingIntent.getBroadcast()。如果这不起作用,您可以使用广播Intent 机制,但您需要定义一个自定义操作,如"my.package.name.UPDATED",然后将该操作放入您的BroadcastReceiver 的清单中。您最大的问题是您不能为此目的使用系统定义的广播 ACTION。 PendingIntent.getActivity() 工作,但它仍然没有更新应用程序。我在session.commit() 做错了吗?应用必须是系统APP还是有Device Owner权限? 您应该能够更新自己的应用程序。如果您查看 logcat,您会看到什么消息?不要过滤 logcat,因为你可能会错过一些重要的东西。看看有没有安装相关的错误 新的 APK 必须与安装的版本具有相同的包名和相同的签名。您不能像这样将调试应用更新为发布应用,反之亦然。

以上是关于自动更新APP,无需用户交互问题==> Permission Denial: not allowed to send broadcast android.intent.action.PACKAG的主要内容,如果未能解决你的问题,请参考以下文章

使用PHP无需用户交互即可连接到Google Drive API

Bluetoothctl 无需任何用户交互

无需用户干预即可自动更新 Android 应用程序

在没有用户交互的情况下启动窗口、处理数据并关闭它?

Bubble更新

无需用户交互即可通过 Api 进行信用卡贷记和借记 / ACH 贷记和借记