Google play filter

问题描述

Vicuna项目使用google play无法搜索到Tango应用(该应用在墨西哥非常受欢迎),导致无法下载。通过其他方式下载APK安装后该应用可正常使用。根据客户需求,我们需要Vicuna项目能从google play上搜索到并下载。

[编辑] 分析过程

对比TRIANGLE能够在google play上搜索到Tango应用并成功下载使用,而Vicuna不能搜索到的表现,怀疑google play本身在应用搜索上有一定的过滤机制,通过查看google官方文档,得到google play有如下一套应用过滤机制:
google play会分析应用的AndroidManifest.xml的信息得到其所需的软硬件要求与当前访问google play的手机系统的软硬件进行对比,通过对比结果返回是否在搜索时显示该应用。
OK,我们现在来大胆猜测下Google play应用完成过滤动作的大致实现步骤(纯属个人无证据的逻辑性猜测):

1.Google play服务器会在应用提交时分析应用AndroidManifest.xml的如下信息,并保存在服务器存储上。
a.<use-sdk>标签
该标签表示应用使用的SDK,如果当前手机提供的SDK未达到此版本,应用搜索不会显示出来,这个很好理解。
b.<use-feature>标签
该标签表示应用会使用到的硬件特性和软件特性。如果手机未达到这些特性要求,应用也不会显示出来。标签内有一个属性“android:required”,如果此标签为false,意为此硬件特性非必须。具体有哪些特性请参考google官方文档 http://developer.android.com/guide/topics/manifest/uses-feature-element.html
c.<use-permission>标签
该标签标示应用会用的权限,但在Android中该标签实际隐含有需支持一些硬件特性,如android:permission:CAMERA就隐含标示需要有android.hardware.camera and android.hardware.camera.autofocus两个硬件feature。其它内容也请查看google官方文档:http://developer.android.com/guide/topics/manifest/uses-feature-element.html
但是服务器上存储的极可能不是permisson,而是经过分析得到的需要包含的硬件特性属性,使用appt工具可以查看没有混淆的应用所需要的 feature,以Tango为例,输入aapt dump badging XXX.APK可以获取当前应用的packageName, versionCode, ApplicationLabel, LauncherActivity, permission, use-feature, locate, screen-densities, native-code等详细信息,截图如下:

Aapt dump badging.png

如上,我们可以清楚的看到该应用需要的硬件特性:
android.hardware.microphone
android.hardware.wifi
android.hardware.touchscreen
注意以上appt列出的硬件特性不是AndroidManifest.xml里面的<use-feature>标签,而是经过分析后的最终需要的硬软件特性(去除use-feature里android:required属性为false的项目和通过permission隐性得到的必须支持的特性)。

2.在用户启动google play应用时,google play会通过开放API获取如下一些手机软硬件信息: a.手机的SDK版本信息,通过android.os.Build.VERSION.SDK获取; b.获取手机支持的软硬件特性,通过PackageManager.getSystemAvailableFeatures()函数获取;获取到这些信息后,Google play会暂时将此存储于内存中。之后用户为了寻觅应用,开始输入关键字进行搜索了,google play本地此时会将从手机中获取的信息传送到google服务器,服务器会进行如下操作:

3.先匹配出该关键字的应用list,然后将搜索出的应用需求的软硬件特性和sdk版本号与上传上来的手机信息进行匹配,一旦有一项不符,就将此应用从list中去掉,最后返回限制了的list给google play,goolge play负责显示出来。

[编辑] Permission从哪里来?feature从哪里来?

作为开发人员,只知道调用API是件很掉价的事情,所以让我们来看看feature是在哪里读进去的。

从我们调用的PackageManager.getSystemAvailableFeatures()可得知其主要从 mAvailableFeatures变量中获取feature信息,mAvailableFeatures是在 readPermissionsFromXml处放入数据的:

......
                } else if ("feature".equals(name)) {
                    String fname = parser.getAttributeValue(null, "name");
                    if (fname == null) {
                        Slog.w(TAG, "<feature> without name at "
                                + parser.getPositionDescription());
                    } else {
                        //Log.i(TAG, "Got feature " + fname);
                        FeatureInfo fi = new FeatureInfo();
                        fi.name = fname;
                        mAvailableFeatures.put(fname, fi);
                    }
                    XmlUtils.skipCurrentTag(parser);
                    continue;

                } 

......

调用readPermissionsFromXml函数的是readPermissions,此函数主要就是遍历system/etc /permissions/目录,获取所有的权限文件XXX.xml然后调用readPermissionsFromXml将他们分类存储起来:

    void readPermissions() {
        // Read permissions from .../etc/permission directory.
        File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
            Slog.w(TAG, "No directory " + libraryDir + ", skipping");
            return;
        }
        if (!libraryDir.canRead()) {
            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
            return;
        }

        // Iterate over the files in the directory and scan .xml files
        for (File f : libraryDir.listFiles()) {
            // We'll read platform.xml last
            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
                continue;
            }

            if (!f.getPath().endsWith(".xml")) {
                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
                continue;
            }
            if (!f.canRead()) {
                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
                continue;
            }

            readPermissionsFromXml(f);
        }

        // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
        final File permFile = new File(Environment.getRootDirectory(),
                "etc/permissions/platform.xml");
        readPermissionsFromXml(permFile);
    

调用readPermissions函数的地方在PackagemanagerService初始化的地方。这就是Permission和feature的来源。

[编辑] Vicuna的确认和结果

通过查看system/etc/permissions/目录下的所有权限文件XXXX.xml发现都没有定义 android.hardware.microphone特性,所以在framework/base/data/etc/添加如下一支内容的文件 android.hardware.microphone.xml即可:

<?xml version="1.0" encoding="utf-8"?>
<!-- This is the standard feature indicating that the device includes microphone. -->
<permissions>
    <feature name="android.hardware.microphone" />
</permissions>

这样当手机SDK版本号和硬软件特性均满足当前应用,我们就可以从google play上搜索到并下载。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值