Android知识android开发专题程序编码

AndroidManifest--你真的理解了吗?

2016-10-24  本文已影响4346人  blink_dagger

最近做二次开发,修改别人代码的时候发现清单文件中多了很多奇怪的属性和标签(自己以前没见过的),在不明白的情况下直接开发出现了很多奇怪的问题。所以痛下决心,重新复习下这些基础知识,以下以6.0系统中的Settings模块源码为例讲解。

<manifest/>标签层:

这是整个清单文件的最上层,用来做一些最基本的声明,如(包名,权限,资源命名空间等)。老规矩,通过栗子来讲解:

<manifest coreApp="true"
          package="com.android.settings"
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:sharedUserId="android.uid.system"
          android:versionCode="20150101"
          android:versionName="3.0.5">
    <original-package android:name="com.android.settings"/>
    <uses-sdk
        android:minSdkVersion="21"
        android:targetSdkVersion="21"/>

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <permission
        android:name="com.cold.permission.appfreeze"
        android:protectionLevel="signatureOrSystem"/>

--*

<application/>标签层:

应用层标签,用来配置我们的apk的整体属性,也可以统一指定所有界面的主题。栗子如下:

    <application
        android:name=".SettingsApp"
        android:allowBackup="false"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/ic_launcher_settings"
        android:label="@string/settings_label"
        android:requiredForAllUsers="true"
        android:supportsRtl="true"
        android:taskAffinity=""
        android:theme="@style/Theme.Aui">
<具体组件/>标签层:

因为</provider>、</service>在实际开发中接触得不多,这部分主要讲解 </activity> 、</receiver>标签。

关于Activity标签的属性,个人最觉得绕和难掌握的就是Intent-filter的匹配规则了,每次使用错了都要去查资料修改,所以这边总结得尽可能仔细。

</activity>

先来一段热身的代码,一个最简单的Activity声明:

        <activity
            android:name="AgedModeActivity"
            android:icon="@drawable/ic_aged_mode"
            android:label="@string/app_name_label"
            android:theme="@android:style/Theme.NoDisplay"
            android:exported="true"
            android:configChanges="orientation|screenSize|fontScale">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

这里还有一点需要注意,如果希望我们的应用有多个入口,每个入口能进入到app的不同Activity中时,光设置这两个属性还不够,还要为它指定一个进程和启动模式。

 android:process=".otherProcess" 
 android:launchMode ="singleInstance"

至于Activity的四种启动模式请各位看官自己复习,就不在这儿重述了。

热身结束,我们就来重点分析<intent-filter>的匹配规则(显式调用只需正确使用包名类名即可,隐式调用才需要考虑匹配的问题)。

        <activity android:name="Settings$WirelessSettingsActivity"
                android:taskAffinity="com.android.settings"
                android:label="@string/wireless_networks_settings_title"
                android:parentActivityName="Settings">
            <intent-filter android:priority="1">
                <action android:name="android.settings.WIRELESS_SETTINGS" />
                <action android:name="android.settings.AIRPLANE_MODE_SETTINGS" />
                <action android:name="android.settings.NFC_SETTINGS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.VOICE_LAUNCH" />
                <data
                    android:scheme="content"
                    android:host="com.android.externalstorage.documents"
                    android:mimeType="vnd.android.document/root" />
            </intent-filter>
            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                android:value="com.android.settings.WirelessSettings" />
            <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
                android:resource="@id/wireless_settings" />
            <!-- Note that this doesn't really show any Wireless settings. -->
            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
                android:value="true" />
        </activity>

当我们通过intent去隐式调用一个Activity时,需要同时匹配注册activity中的action、category、data才能正常启动,而这三个属性的匹配规则也略有不同。

额外扩展一些关于activity的属性:
    private void getMetaData() {
        PDebug.Start("getMetaData");
        try {
            ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
                    PackageManager.GET_META_DATA);
            if (ai == null || ai.metaData == null) return;
            mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
            mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);

            // Check if it has a parent specified and create a Header object
            final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
            String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
            if (parentFragmentClass != null) {
                mParentHeader = new Header();
                mParentHeader.fragment = parentFragmentClass;
                if (parentHeaderTitleRes != 0) {
                    mParentHeader.title = getResources().getString(parentHeaderTitleRes);
                }
            }
        } catch (NameNotFoundException nnfe) {
            // No recovery
        }
        PDebug.End("getMetaData");
    }
</receiver>

关于receiver,个人觉得容易混淆的就一个permission问题:

    <receiver
        android:name="com.android.settings.AliAgeModeReceiver"
        android:permission="com.android.settings.permission.SWITH_SETTING">
        <intent-filter>
            <action android:name="com.android.settings.action.SWITH_AGED_MODE"/>
        </intent-filter>
    </receiver>

起初认为这是receiver中处理一些操作需要使用到此权限,后来查阅资料后发现是通过在</receiver>中添加permission标签,我可以发送一些敏感的广播,只有添加了该permission的receiver才能接收到,而不让其他的应用收到。栗:

Intent intent = new Intent("com.android.settings.action.SWITH_AGED_MODE");
sendBroadcast(intent,"com.android.settings.permission.SWITH_SETTING");

这要就只有我们自己的接收者才能收到该广播,但是当我们

Intent intent = new Intent("com.android.settings.action.SWITH_AGED_MODE");
sendBroadcast(intent);

则所有有此action的接收者都能收到我们发出的广播。
总结来说就是:

  1. 一些敏感的广播并不想让第三方的应用收到 ;
  2. 要限制自己的Receiver接收某广播来源,避免被恶意的同样的ACTION的广播所干扰。

--*

11.01更新:
码字不易,给个赞呗~
上一篇下一篇

猜你喜欢

热点阅读