以编程方式安装/卸载APKs(PackageManager vs Intents)

我的应用程序安装了其他应用程序,并且需要跟踪它安装的应用程序。 当然,这可以通过简单地保存已安装应用程序的列表来实现。 但这不应该是必要的! PackageManager负责维护installedBy(a,b)关系。 实际上,根据API,它是:

public abstract String getInstallerPackageName(String packageName) - 检索安装包的应用程序的包名称。 这标识了该软件包来自哪个市场。

目前的做法

使用Intent安装APK

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
startActivity(intent);

使用Intent卸载APK:

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

这显然不是Android Market安装/卸载软件包的方式。 他们使用更丰富的PackageManager版本。 通过从Android Git存储库下载Android源代码可以看到这一点。 以下是与Intent方法相对应的两个隐藏方法。 不幸的是,它们不适用于外部开发人员。 但也许他们会在未来?

更好的方法

使用PackageManager安装APK

/**
 * @hide
 * 
 * Install a package. Since this may take a little while, the result will
 * be posted back to the given observer.  An installation will fail if the calling context
 * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
 * package named in the package file's manifest is already installed, or if there's no space
 * available on the device.
 *
 * @param packageURI The location of the package file to install.  This can be a 'file:' or a
 * 'content:' URI.
 * @param observer An observer callback to get notified when the package installation is
 * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
 * called when that happens.  observer may be null to indicate that no callback is desired.
 * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
 * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
 * @param installerPackageName Optional package name of the application that is performing the
 * installation. This identifies which market the package came from.
 */
public abstract void installPackage(
        Uri packageURI, IPackageInstallObserver observer, int flags,
        String installerPackageName);

使用PackageManager卸载APK

/**
 * Attempts to delete a package.  Since this may take a little while, the result will
 * be posted back to the given observer.  A deletion will fail if the calling context
 * lacks the {@link android.Manifest.permission#DELETE_PACKAGES} permission, if the
 * named package cannot be found, or if the named package is a "system package".
 * (TODO: include pointer to documentation on "system packages")
 *
 * @param packageName The name of the package to delete
 * @param observer An observer callback to get notified when the package deletion is
 * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
 * called when that happens.  observer may be null to indicate that no callback is desired.
 * @param flags - possible values: {@link #DONT_DELETE_DATA}
 *
 * @hide
 */
public abstract void deletePackage(
        String packageName, IPackageDeleteObserver observer, int flags);

差异

  • 当使用意图时,本地软件包管理器不知道安装源自哪个应用程序。 具体来说,getInstallerPackageName(...)返回null。

  • 隐藏方法installPackage(...)将安装程序包名称作为参数,并且很可能能够设置此值。

  • 是否可以使用意图指定包安装程序名称? (也许安装程序包的名称可以作为额外的安装意图添加?)

    提示:如果您想下载Android源代码,您可以按照以下步骤操作:下载源代码树。 要提取* .java文件并根据软件包层次结构将它们放入文件夹中,可以查看以下简洁的脚本:在Eclipse中查看Android源代码。


    这目前不适用于第三方应用程序。 请注意,即使使用反射或其他技巧来访问installPackage()也无济于事,因为只有系统应用程序才能使用它。 (这是因为它是低级别的安装机制,在用户批准权限之后,因此普通应用程序无法访问该安全机制。)

    此外,installPackage()函数参数在平台版本之间经常发生变化,所以您尝试访问它的任何内容都将在各种其他版本的平台上失败。

    编辑:

    另外值得指出的是,这个InstallerPackage最近才刚刚添加到平台(2.2?)中,最初并未实际用于跟踪谁安装了应用程序 - 平台使用它来确定在向该应用程序,用于实现Android反馈。 (这也是API方法参数改变的时代之一。)在推出后至少很长一段时间,Market还没有使用它来跟踪它安装的应用程序(它可能还没有使用它),而只是用它来设置Android反馈应用程序(与市场分开)作为“所有者”来处理反馈。


    [卸载]

    怎么样:

    Intent intent = new Intent(Intent.ACTION_DELETE);
    intent.setData(Uri.parse("package:com.example.mypackage"));
    startActivity(intent);
    

    用于卸载。 似乎更容易...


    API级别14引入了两个新操作:ACTION_INSTALL_PACKAGE和ACTION_UNINSTALL_PACKAGE。 这些操作允许您传递EXTRA_RETURN_RESULT布尔额外以获取(未)安装结果通知。

    调用卸载对话框的示例代码:

    String app_pkg_name = "com.example.app";
    int UNINSTALL_REQUEST_CODE = 1;
    
    Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);  
    intent.setData(Uri.parse("package:" + app_pkg_name));  
    intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
    startActivityForResult(intent, UNINSTALL_REQUEST_CODE);
    

    并在您的Activity#onActivityResult方法中接收通知:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == UNINSTALL_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                Log.d("TAG", "onActivityResult: user accepted the (un)install");
            } else if (resultCode == RESULT_CANCELED) {
                Log.d("TAG", "onActivityResult: user canceled the (un)install");
            } else if (resultCode == RESULT_FIRST_USER) {
                Log.d("TAG", "onActivityResult: failed to (un)install");
            }
        }
    }
    
    链接地址: http://www.djcxy.com/p/41877.html

    上一篇: install / uninstall APKs programmatically (PackageManager vs Intents)

    下一篇: How to launch the Google Play intent in 'Give Feedback' mode on Android?