Android:关于InstallerPackgeName的二三事

来源:互联网 发布:好的漫画软件 编辑:程序博客网 时间:2024/05/16 14:38

【转载请注明出处】
作者:DrkCore
原文:http://blog.csdn.net/drkcore/article/details/76290656

在应用开发中我们通常会在应用的打包脚本中标注多个渠道,用以统计应用在不同的应用市场中的效果。这当然是一个不错的做法,不过有的时候我们还想要知道用户是通过什么方式安装应用的,此时就需要使用 InstallerPackageName 了:

package android.content.pm;public abstract class PackageManager {    /**     * Retrieve the package name of the application that installed a package. This identifies     * which market the package came from.     *     * @param packageName The name of the package to query     */    public abstract String getInstallerPackageName(String packageName);}

我们可以通过 PackageManager.getInstallerPackageName(String pack) 来获取某个应用安装时使用的安装器的名称。看起来非常的方便但是该方法并不能代替渠道号的作用。

常见的返回值

大部分系统应用和通过 ADB 安装的应用(包括使用 AS 运行安装)会返回 null,而直接打开 APK 安装的则会返回 com.google.android.packageinstaller。以下是一些例子:

Package Installer Desc com.android.mms null 系统短信服务 com.android.mms.service null 系统短信服务 core.demo null 通过 Adb 直接安装的应用 net.openvpn.openvpn com.google.android.packageinstaller 设备默认安装器 com.baidu.tieba_mini com.google.android.packageinstaller 设备默认安装器 com.netease.cloudmusic com.google.android.packageinstaller 设备默认安装器

产商应用市场

笔者测试的设备是 SAMSUNG S7E 9350,部分系统级应用使用的安装器是三星应用市场,如下:

Package Installer Desc com.sec.android.app.samsungapps com.sec.android.app.samsungapps 三星应用市场 com.samsung.android.themestore com.samsung.android.themestore 三星主题商店 com.enhance.gameservice com.enhance.gameservice 三星的游戏服务

由此可以合理推测小米、华为等产商也应该会用同样的做法。不过笔者手头并没有这些设备,如果知道的同学欢迎留言告知。

Google Play 和第三方应用市场

Google Play 的安装器名称大部分是 com.android.vending。如果你的统计量比较大的话你可能还会遇到一个名称是 com.google.android.feedback,它代表的是旧版的谷歌市场,不过其占有量现在应该很低了。

Package Installer Desc com.google.android.gm com.android.vending GooglePlay com.android.chrome com.android.vending GooglePlay 笔者并没有旧版的谷歌市场 com.google.android.feedback 旧版的谷歌市场

Google Play 毕竟是官家的市场,installer 的返回值是有保证的。但是第三方的市场有可能并不遵守这样的规则。

笔者测试中使用了百度应用市场发现其安装器是 com.google.android.packageinstaller 也就是系统默认的安装器。普通应用想要发起安装 APK 的请求都是通过以下的 Intent 来安装的,此时打开的界面就是默认安装器:

Intent intent = new Intent(Intent.ACTION_VIEW);intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setDataAndType(Uri.parse("file://" + apk), "application/vnd.android.package-archive");context.startActivity(intent);

猜测原因是因为第三方应用市场在未 Root 的设备中本身也只是普通的应用所以并无权限,而产商应用市场和 Google Play 持有系统签名可以设置自己的安装器名称。

但由于条件原因笔者并未测试过 Root 后开启静默安装的百度市场的行为,如有同学知道的还请告知。

更新版本对 Installer 的影响

先说结论:更新应用会根据安装方法刷新 installerName

笔者设备上的百度地图原本是通过三星应用市场安装的:

这里写图片描述

在使用了百度应用市场更新后其 installer 就变成了默认安装器:

这里写图片描述

笔者也试过用 Google Play 来更新应用,结果和上述结论一致:

这里写图片描述

InstallerName 某种程度上算是实时变化的,这一点和部分数据统计 SDK 比如友盟就不一样。按照友盟的策略应用在一台设备上的渠道号只认准首次安装时的值,就算后期用户手动换了渠道后也是一样。在实际开发中这一点需要注意。

如何修改渠道号

Adb 命令修改

pm install -i installerName file.apk 可以在安装时修改 installerName

该方法可以使用任意的值,比如笔者在测试中就是用了中文作为 installerName:

hero2qltechn:/sdcard $ pm install -i 这个是使用adb写入的包名 app-debug.apk

这里写图片描述

在测试的时候可以使用该方法来验证结果。

代码修改

PackageManager.setInstallerPackage() 可以修改 installerName 但是限制比较多

/*** Change the installer associated with a given package.  There are limitations* on how the installer package can be changed; in particular:* <ul>* <li> A SecurityException will be thrown if <var>installerPackageName</var>* is not signed with the same certificate as the calling application.* <li> A SecurityException will be thrown if <var>targetPackage</var> already* has an installer package, and that installer package is not signed with* the same certificate as the calling application.* </ul>** @param targetPackage The installed package whose installer will be changed.* @param installerPackageName The package name of the new installer.  May be* null to clear the association.*/public abstract void setInstallerPackageName(String targetPackage, String installerPackageName);

该方法并不要求任何的特殊权限,但是要求调用者要和要修改成的安装器对应的应用要有相同的签名。

实测中 installerPackageName 对应的应用必须已安装,由于签名的原因笔者只能将之设置成自身的名字:

这里写图片描述

其他

关于海外市场的开发者可能知道某些广告 SDK 提供商最近修改了相关政策不再向非 Google Play 下载的应用提供广告。出于好奇笔者找了下其 SDK 发现了如下代码:

这里写图片描述

这里写图片描述

其实现就是获取包名然后再 PackageManager.getInstallerPackageName 的,嗯,看来大家的想法都是差不多的。

参阅资料:

  • StackOverFlow: Can PackageManager.getInstallerPackageName() tell me that my app was installed from Amazon app store?
    https://stackoverflow.com/questions/13289748/can-packagemanager-getinstallerpackagename-tell-me-that-my-app-was-installed-f

  • StackOverFlow: getInstallerPackageName returns null
    https://stackoverflow.com/questions/12593621/getinstallerpackagename-returns-null

  • CoderWall: Check if an APK is from Google Play
    https://coderwall.com/p/fipesa/check-if-an-apk-is-from-google-play

原创粉丝点击