【问题标题】:PackageInstaller "Silent install and uninstall of apps by Device Owner” - Android M PreviewPackageInstaller“设备所有者静默安装和卸载应用程序” - Android M Preview
【发布时间】:2015-12-05 01:05:14
【问题描述】:

PackageInstaller (https://developer.android.com/reference/android/content/pm/PackageInstaller.html) 似乎已从 API 21 (Lollipop) 开始添加,但是我还没有找到任何关于如何通过此 API 安装 APK 的可靠代码示例。任何代码帮助将不胜感激。

我正在调查适用于 Android M Preview 的 COSU/Kiosk 应用程序,并试图通过 PackageInstaller API 实现新功能“设备所有者静默安装和卸载应用程序”(https://developer.android.com/preview/api-overview.html#afw)。

找到了这些,但没有帮助:How to install/update/remove APK using "PackageInstaller" class in Android L? What's "PackageInstaller" class on Lollipop, and how to use it?

也没有找到任何 Android 示例应用。

提前致谢。

【问题讨论】:

标签: silent-installer kiosk-mode android-6.0-marshmallow device-owner packageinstaller


【解决方案1】:

这可以从 Android 6.0 及更高版本开始。

  • 让您的应用成为设备所有者。

一旦您的应用获得设备所有者权限,我们就可以静默安装、卸载和更新,无需任何用户干预。

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();
    }

卸载:

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());

在此repo 中完成设备所有者演示应用程序。

【讨论】:

  • 这里的 createIntentSender 是什么..?
  • ACTION_INSTALL_COMPLETE 也未定义!是 public static String ACTION_INSTALL_COMPLETE = 'someString' 还是特定的 android 常量?
  • 不是 android 特定的.. github.com/googlesamples/android-testdpc 检查这个示例应用程序。
  • 请注意,您必须将 android.permission.DELETE_PACKAGES 添加到清单中才能进行卸载(在 Api 级别 22 或以下测试)
  • @woprandi 设备所有者 api 支持从 Android 6.0 及更高版本进行静默安装/卸载。
【解决方案2】:

想通了,代码如下:

    try
    {
        PackageInstaller pi = app.getPackageManager().getPackageInstaller();
        int sessId          = pi.createSession(new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));

        PackageInstaller.Session session = pi.openSession(sessId);

        // .. write updated APK file to out


        long sizeBytes = 0;
        final File file = new File(filepathApk);
        if (file.isFile())
        {
            sizeBytes = file.length();
        }

        InputStream in = null;
        OutputStream out = null;

        in = new FileInputStream(filepathApk);
        out = session.openWrite("my_app_session", 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);
        }
        session.fsync(out);
        in.close();
        out.close();

        System.out.println("InstallApkViaPackageInstaller - Success: streamed apk " + total + " bytes");

        // fake intent
        Context app = this;
        Intent intent = new Intent(app, AlarmReceiver.class);
        PendingIntent alarmtest = PendingIntent.getBroadcast(app,
                1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        session.commit(alarmtest.getIntentSender());
        session.close();

    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }

【讨论】:

  • 'AlarmReceiver' 类有什么作用?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-31
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 2011-06-26
  • 2012-12-26
相关资源
最近更新 更多