首发于极光日报
Android Package Name vs. Application ID

Android Package Name vs. Application ID

简评:最熟悉的地方也会有大学问。

对于 Android 开发者来说,Package Name 应当再熟悉不过了,或许有些同学还注意到了 App 的 build.gradle 中有一个 applicationId,它的值通常都和包名一致,但其实二者是存在区别的。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  package="com.stylingandroid.packagename">
 
  ...
</manifest>

可以看到这里有一个包名:com.stylingandroid.packagename,而我们这里在 build.gradle 中为 applicationId 加上 .release 和 .debug 两个不同的后缀:

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.stylingandroid.packagename"
        minSdkVersion 23
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            applicationIdSuffix ".release"
        }
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

我们比较打包出来两个 APK 的 Manifest 文件,可以观察下其中 package 的值:

可以发现应用最终的包名其实是由 applicationId 决定的,而之前 Manifest 中的 package 值主要是做两件事:

  • 指明类的路径。比如我们在 manifest 文件中声明 <activity android:name=".MainActivity">,实际会被解析为 com.stylingandroid.packagename.MainActivity
  • 指明 R.java 文件的路径,对于本文的例子来说就是 com.stylingandroid.packagename.R

这些在官方文档中都有讲解,主要需要注意的是文档的最后一段:

Although you may have a different name for the manifest package and the Gradle applicationId, the build tools copy the application ID into your APK’s final manifest file at the end of the build

注意文档中所说的,Android 是在程序编译的最后才将 application ID 拷贝进 APK 的 manifest 文件的。

如果你像上面那样在 buildTypes 中修改了 applicationId 值,那么在代码中想要获取到应用包名就需要注意,看看下面的代码:

public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
 
       TextView packageNameTextView = (TextView) findViewById(R.id.package_name);
       TextView applicationIdTextView = (TextView) findViewById(R.id.application_id);
 
       packageNameTextView.setText(getString(R.string.package_name, BuildConfig.class.getPackage().toString()));
       applicationIdTextView.setText(getString(R.string.application_id, BuildConfig.APPLICATION_ID));
    }
}
结果分别为:
Package Name: package com.stylingandroid.packagename
Application ID: com.stylingandroid.packagename.debug

那为什么 Android 要在编译的最后才将 application ID 拷贝进 manifest 文件中呢?

理由很简单,如果 BuildConfig.java 和 R.java 文件使用了 applicationId 而不是 package name,编译的时候路径会出错。


原文:Package Name vs. Application ID

扩展阅读:


欢迎关注:知乎专栏「极光日报」,每天为 Makers 导读三篇优质英文文章。

编辑于 2017-03-08 14:43