Issue
I want to update the APP automatically when a new version is available without user interaction, suppose a new version is available and it is downloaded to Downloads directory in android.
I followed the following example.
Java Sample: https://stackoverflow.com/a/51705614
Kotlin Sample: https://www.sisik.eu/blog/android/dev-admin/update-app
facing this exception
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();
}
}
}
}
and inside my MainActivity.java on button click calling CustomPackageInstaller.installPackage() written in above class
File file= new File(filePath);
InputStream targetStream = new FileInputStream(file);
CustomPackageInstaller.installPackage(
MainActivity.this,
"2",
"com.odine.autoupdateapppractice",
targetStream);
Solution
The error message you are getting pretty much tells you what the problem is. You have requested that the package installer notify you on completion by sending a broacast Intent
with ACTION = android.intent.action.PACKAGE_ADDED
. This broadcast Intent
can only be sent by the Android framework. Regular apps cannot send this broadcast Intent
.
You should use an explicit Intent
, where you specify the component (package name and class name) for this purpose. You can have the package installer launch an Activity
or a BroadcastReceiver
for this purpose.
NOTE: Your app must be device owner to be able to do this without user interaction.
Answered By - David Wasser
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.