使用XmlResourceParser解析AndroidManifest.xml无法按预期工作

时间:2018-03-13 19:51:51

标签: java android xml parsing xml-parsing

我需要解析AndroidManifest.xml以检索通过PackageManager无法获得的其他一些信息。

我有以下代码:

try
{
    AssetManager assetManager = createPackageContext(getPackageName(), 0).getAssets();
    XmlResourceParser xml = assetManager.openXmlResourceParser("AndroidManifest.xml");
    int eventType = xml.getEventType();

    while (eventType != XmlPullParser.END_DOCUMENT)
    {
        if(eventType == XmlPullParser.START_DOCUMENT) {
            Log.d(TAG, "START_DOCUMENT");
        } else if(eventType == XmlPullParser.START_TAG) {
            Log.d(TAG, "START_TAG: " + xml.getName());
        } else if(eventType == XmlPullParser.END_TAG) {
            Log.d(TAG, "END_TAG: " + xml.getName());
        } else if(eventType == XmlPullParser.TEXT) {
            Log.d(TAG, "TEXT: " + xml.getText());
        }
        eventType = xml.next();
    }

    xml.close();
}
catch ( XmlPullParserException
      | PackageManager.NameNotFoundException
      | IOException ignore) { }

我希望从XML文件中获取所有标签,但我得到的只是:

START_DOCUMENT
START_DOCUMENT
START_TAG: manifest
END_TAG: manifest

......这不是我的预期。

我不确定为什么START_DOCUMENT有两次,但最让我烦恼的是我在<manifests>标签内没有得到任何标签。

我是否在解析时出错或者那些标签根本不可用?

2 个答案:

答案 0 :(得分:2)

穆罕默德的代码适用于非即时运行版本。

使用即时运行,设备上的APK只会模糊地与将要部署到制作中的实际APK相似。一些核心APK可能是真实的APK中的内容,但是你的应用程序的其余部分会被推送为某种形式的附加组件,即运行环境可以将它们混合在一起以创建类似于你的应用程序运行的东西。这样做的好处是这些附加组件可以快速推送,因为它们更小,并且不需要完整的设备安装。

缺点是即时运行应用不是你的APK,所以在APK内查看的内容可能在Instant Run版本上的工作方式与在常规版本上的工作方式不同。

我很惊讶清单是Instant Run环境可以基于这些附加组件动态合成的东西。话虽这么说,将清单作为资源阅读肯定有资格作为&#34;不寻常&#34;等等,回想起Instant Run破坏了这段代码并不令人震惊。

因此,如果您真的需要这个read-the-manifest-XML功能,那么您需要为IDE禁用Instant Run。或者,找到一些不需要读取清单XML的其他解决方案(例如,保存所需的&#34;哪些运行时权限是可选的?&#34; Java static字段中的信息)。

答案 1 :(得分:1)

您需要拨打xml.next()而不是xml.getEventType(),因为您正在处理文件,而next()方法总是从零开始作为文件起点,如果文件为空,则以 1 的值结束。

我希望这会有所帮助。

// for the sake of dealing with a file
int eventType = xml.next();

完整代码:

final String TAG = "cccc";

try
{
    AssetManager assetManager = createPackageContext(getPackageName(), 0).getAssets();
    XmlResourceParser xml = assetManager.openXmlResourceParser("AndroidManifest.xml");
    int eventType = xml.next();

    while (eventType != XmlPullParser.END_DOCUMENT)
    {
        if (eventType == XmlPullParser.START_DOCUMENT) {
            Log.d(TAG, "START_DOCUMENT");
        } else if(eventType == XmlPullParser.START_TAG) {
            Log.d(TAG, "START_TAG: " + xml.getName());
        } else if(eventType == XmlPullParser.END_TAG) {
            Log.d(TAG, "END_TAG: " + xml.getName());
        } else if(eventType == XmlPullParser.TEXT) {
            Log.d(TAG, "TEXT: " + xml.getText());
        }
        eventType = xml.next();
    }

    xml.close();
}
catch ( XmlPullParserException
      | PackageManager.NameNotFoundException
      | IOException ignore) { }

在实际设备上运行时的结果

 D/cccc: START_TAG:START_DOCUMENT
 D/cccc: START_TAG: manifest
 D/cccc: START_TAG: uses-sdk
 D/cccc: END_TAG: uses-sdk
 D/cccc: START_TAG: uses-permission
 D/cccc: END_TAG: uses-permission
 D/cccc: START_TAG: uses-permission
 D/cccc: END_TAG: uses-permission
.
.
.
 D/cccc: END_TAG: application
 D/cccc: END_TAG: manifest

当我使用模拟器运行代码时遇到了同样的问题。

参考this great post代码将按预期工作。