简体   繁体   English

如何使用Android L中的“PackageInstaller”类安装/更新/删除APK?

[英]How to install/update/remove APK using “PackageInstaller” class in Android L?

Plz check below classe & give me the suggestion for how to use them https://developer.android.com/reference/android/content/pm/PackageInstaller.html https://developer.android.com/reference/android/content/pm/PackageInstaller.Session.html Plz检查下面的classe并给我如何使用它们的建议https://developer.android.com/reference/android/content/pm/PackageInstaller.html https://developer.android.com/reference/android/content /pm/PackageInstaller.Session.html

So please give me an example to install/update/remove app. 所以请给我一个安装/更新/删除应用程序的示例。 Can it be possible that the new application will install in device profile owner? 新应用程序是否可能安装在设备配置文件所有者中?

It is possible without System permissions from Android M onwards . 没有Android M以上的系统权限就可以。

if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
        == PackageManager.PERMISSION_GRANTED)
        || (installerUid == Process.ROOT_UID)
        || mIsInstallerDeviceOwner) {
    mPermissionsAccepted = true;
} else {
    mPermissionsAccepted = false;
}

Silent install and uninstall of apps by Device Owner: 设备所有者静默安装和卸载应用程序:

A Device Owner can now silently install and uninstall applications using the PackageInstaller APIs, independent of Google Play for Work. 设备所有者现在可以使用PackageInstaller API以独立于Google Play for Work的方式静默安装和卸载应用程序。

More in this link. 更多链接。


This is possible from Android 6.0 and up. 这可以在Android 6.0及更高版本中使用。

  • Make your app the Device owner. 使您的应用成为设备所有者。

Once your app gets the Device owner permission, we can install, uninstall and update silently without any user intervention. 一旦您的应用获得了设备所有者权限,我们就可以无需任何用户干预即可静默安装,卸载和更新。

public static boolean installPackage(Context context, InputStream in, String packageName)
        throws IOException {
    PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
    PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
            PackageInstaller.SessionParams.MODE_FULL_INSTALL);
    params.setAppPackageName(packageName);
    // set params
    int sessionId = packageInstaller.createSession(params);
    PackageInstaller.Session session = packageInstaller.openSession(sessionId);
    OutputStream out = session.openWrite("COSU", 0, -1);
    byte[] buffer = new byte[65536];
    int c;
    while ((c = in.read(buffer)) != -1) {
        out.write(buffer, 0, c);
    }
    session.fsync(out);
    in.close();
    out.close();

    session.commit(createIntentSender(context, sessionId));
    return true;
}



private static IntentSender createIntentSender(Context context, int sessionId) {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                context,
                sessionId,
                new Intent(ACTION_INSTALL_COMPLETE),
                0);
        return pendingIntent.getIntentSender();
    }

Uninstall: 卸载:

String appPackage = "com.your.app.package";
Intent intent = new Intent(getActivity(), getActivity().getClass());
PendingIntent sender = PendingIntent.getActivity(getActivity(), 0, intent, 0);
PackageInstaller mPackageInstaller = getActivity().getPackageManager().getPackageInstaller();
mPackageInstaller.uninstall(appPackage, sender.getIntentSender());

Git repo here . Git repo在这里

You cannot silently install a third party application in the newly created user with PackageInstaller.Session.commit() without specific "rights". 您无法使用PackageInstaller.Session.commit()在新创建的用户中静默安装第三方应用程序,而无需特定的“权限”。
You either need : 你要么需要:

  • the INSTALL_PACKAGES permission. INSTALL_PACKAGES权限。 But this permission is not available for third-party application. 但是此权限不适用于第三方应用程序。 So even with your profile owner app, you won't have this specific permission. 因此,即使使用您的个人资料所有者应用,您也不会拥有此特定权限。
  • Run the process as ROOT_UID . ROOT_UID运行该过程。 Which means you'll have to root the device. 这意味着您必须根设备。

From the Android source code : 来自Android源代码

if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid) == PackageManager.PERMISSION_GRANTED) 
   || (installerUid == Process.ROOT_UID)) {
    mPermissionsAccepted = true;
} else {
    mPermissionsAccepted = false;
}

If you neither have root access and the INSTALL_PACKAGES permission, then a message will be prompted to the user to ask if he confirms the permissions. 如果您既没有root访问权限也没有INSTALL_PACKAGES权限,则会提示用户询问他是否确认了权限。 This confirmation is then used during the commit process of the PackageInstaller's session. 然后在PackageInstaller's会话的提交process中使用此确认。 Obviously, in this case, this is not transparent, since the user will have to manually confirm the installation of your apps. 显然,在这种情况下,这不是透明的,因为用户必须手动确认您的应用程序的安装。

The install method @amalBit provided did not work for me. 提供的安装方法@amalBit对我不起作用。 It's strange since this is how it is implemented in the Google Sample . 这很奇怪,因为这是在Google Sample中实现的方式

This answer helped me to find a solution. 这个答案帮助我找到了解决方案。 I had to change some parts of the code. 我不得不改变代码的某些部分。 Here is my implementation: 这是我的实现:

public static void installPackage(Context context, InputStream inputStream)
        throws IOException {
    PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
    int sessionId = packageInstaller.createSession(new PackageInstaller
            .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));
    PackageInstaller.Session session = packageInstaller.openSession(sessionId);

    long sizeBytes = 0;

    OutputStream out = null;
    out = session.openWrite("my_app_session", 0, sizeBytes);

    int total = 0;
    byte[] buffer = new byte[65536];
    int c;
    while ((c = inputStream.read(buffer)) != -1) {
        total += c;
        out.write(buffer, 0, c);
    }
    session.fsync(out);
    inputStream.close();
    out.close();

    // fake intent
    IntentSender statusReceiver = null;
    Intent intent = new Intent(context, SomeActivity.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
            1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    session.commit(pendingIntent.getIntentSender());
    session.close();
}

This method can be called like this: 可以像这样调用此方法:

        InputStream inputStream = getActivity().getAssets().open("my_awesome_app.apk");
        InstallationHelper.installPackage(getActivity(), inputStream);

This works for me as well, although my device owner restricts the installation of apps and unknown sources by the user. 虽然我的设备所有者限制用户安装应用程序和未知来源,但这对我也有用。 Even if I running this example as device admin, I've got the java.lang.SecurityException: User restriction prevents installing. 即使我将此示例作为设备管理员运行,我也得到了java.lang.SecurityException: User restriction prevents installing.

openSession is checking for permissions. openSession正在检查权限。 With this simple modificaton it is possible to reset the user restrictions only during a short method call. 通过这种简单的修改,可以仅在短方法调用期间重置用户限制。

public static DevicePolicyManager getDpm(Context context) {
    return (DevicePolicyManager)context.getSystemService(Context.DEVICE_POLICY_SERVICE);
}

public static ComponentName getAdmin(Context context) {
    return new ComponentName(context, MyDevicePolicyReceiver.class);
}

public static void addMyRestrictions(Context context) {
   getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS);
   getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
}

public static void clearMyRestrictions(Context context) {    
   getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS);
   getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
}

public static void installPackage(Context context, InputStream inputStream)
    throws IOException {
    PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
    int sessionId = packageInstaller.createSession(new PackageInstaller
        .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));

    //openSession checks for user restrictions
    clearMyRestrictions(context);
    PackageInstaller.Session session = packageInstaller.openSession(sessionId);
    addMyRestrictions(context);

    long sizeBytes = 0;

    OutputStream out = null;
    out = session.openWrite("my_app_session", 0, sizeBytes);

    int total = 0;
    byte[] buffer = new byte[65536];
    int c;
    while ((c = inputStream.read(buffer)) != -1) {
        total += c;
        out.write(buffer, 0, c);
    }
    session.fsync(out);
    inputStream.close();
    out.close();

    // fake intent
    IntentSender statusReceiver = null;
    Intent intent = new Intent(context, SomeActivity.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
        1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    session.commit(pendingIntent.getIntentSender());
    session.close();
}

Please take care of exception handling. 请注意异常处理。

You simply clear your restrictions 你只需清除你的限制

public static DevicePolicyManager getDpm(Context context) {
    return (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
}

public static ComponentName getAdmin(Context context) {
    return new ComponentName(context, MyDevicePolicyReceiver.class);
}

public static void addMyRestrictions(Context context) {
    getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS);
    getDpm(context).addUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
}

public static void clearMyRestrictions(Context context) {
    getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_APPS);
    getDpm(context).clearUserRestriction(getAdmin(context), UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
}

public static void installPackage(Context context, InputStream inputStream)
        throws IOException {
    PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
    int sessionId = packageInstaller.createSession(new PackageInstaller
            .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));

    //openSession checks for user restrictions
    clearMyRestrictions(context);
    PackageInstaller.Session session = packageInstaller.openSession(sessionId);

    long sizeBytes = 0;

    OutputStream out = null;
    out = session.openWrite("my_app_session", 0, sizeBytes);

    int total = 0;
    byte[] buffer = new byte[65536];
    int c;
    while ((c = inputStream.read(buffer)) != -1) {
        total += c;
        out.write(buffer, 0, c);
    }
    session.fsync(out);
    inputStream.close();
    out.close();

    // fake intent
    IntentSender statusReceiver = null;
    Intent intent = new Intent(context, SomeActivity.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
            1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    session.commit(pendingIntent.getIntentSender());
    session.close();
}

In Android Api-21 below is code snippet via which we can install apk silently. 在Android Api-21下面是代码片段,我们可以通过它静默安装apk。

private void runInstallWrite() throws IOException, RemoteException {
        long sizeBytes = -1;

        String opt;
        while ((opt = nextOption()) != null) {
            if (opt.equals("-S")) {
                sizeBytes = Long.parseLong(nextOptionData());
            } else {
                throw new IllegalArgumentException("Unknown option: " + opt);
            }
        }

        final int sessionId = Integer.parseInt(nextArg());
        final String splitName = nextArg();

        String path = nextArg();
        if ("-".equals(path)) {
            path = null;
        } else if (path != null) {
            final File file = new File(path);
            if (file.isFile()) {
                sizeBytes = file.length();
            }
        }

        final SessionInfo info = mInstaller.getSessionInfo(sessionId);

        PackageInstaller.Session session = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            session = new PackageInstaller.Session(mInstaller.openSession(sessionId));

            if (path != null) {
                in = new FileInputStream(path);
            } else {
                in = new SizedInputStream(System.in, sizeBytes);
            }
            out = session.openWrite(splitName, 0, sizeBytes);

            int total = 0;
            byte[] buffer = new byte[65536];
            int c;
            while ((c = in.read(buffer)) != -1) {
                total += c;
                out.write(buffer, 0, c);

                if (info.sizeBytes > 0) {
                    final float fraction = ((float) c / (float) info.sizeBytes);
                    session.addProgress(fraction);
                }
            }
            session.fsync(out);

            System.out.println("Success: streamed " + total + " bytes");
        } finally {
            IoUtils.closeQuietly(out);
            IoUtils.closeQuietly(in);
            IoUtils.closeQuietly(session);
        }
    }

The above code is been took from Framework here 上面的代码是由框架了这里

Can i use this code with device_owner or normal user in LoLiipop ? 我可以在LoLiipop中将此代码与device_owner或普通用户一起使用吗?

Answer - No Since there are apis which is been @hide tag in android frameworks, although PackageManager.Session is introduced in API 21 but we cannot use new PAckageManager.Session() since it @hide in API 21. 答案 - 否由于在android框架中有@hide标签的apis,虽然在API 21中引入了PackageManager.Session但我们不能使用新的PAckageManager.Session(),因为它在API 21中@hide。

If you wanna still use this code via framework.jar , you need to build Lolippop source code and extract jar from out/..../framework.jar and call above apis. 如果您仍想通过framework.jar使用此代码,则需要构建Lolippop源代码并从/..../ framework.jar中提取jar并调用apis以上。

INSTALL: 安装:

Intent promptInstall = new Intent(Intent.ACTION_VIEW);
        promptInstall.setDataAndType(Uri.fromFile(new File(Environment
                .getExternalStorageDirectory() + "/download/" + APK_NAME)),
                "application/vnd.android.package-archive");
        promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(promptInstall);

UNINSTALL: 卸载:

Intent intent = new Intent(Intent.ACTION_DELETE, Uri.fromParts("package",
getPackageManager().getPackageArchiveInfo(apkUri.getPath(), 0).packageName,null));
startActivity(intent);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM