你如何获取你的Android应用程序的构建/版本号?

1574
我需要弄清楚如何为我的Android应用程序获取或生成一个版本号。我需要在用户界面中显示版本号。
我需要在AndroidManifest.xml文件中做一些操作吗?

1
重复的问题:https://dev59.com/1m855IYBdhLWcg3wNhd1 - Idemax
37
获取版本号使用int versionCode = BuildConfig.VERSION_CODE;,获取版本名使用String versionName = BuildConfig.VERSION_NAME; - Lukas
39个回答

2292
如果你正在使用Gradle插件/Android Studio,从版本0.7.0开始, 版本代码和版本名称可以在BuildConfig中静态获取。 确保导入你的应用程序包,而不是另一个BuildConfig:
import com.yourpackage.BuildConfig;
...
int versionCode = BuildConfig.VERSION_CODE;
String versionName = BuildConfig.VERSION_NAME;

没有需要上下文对象!
此外,请确保在您的build.gradle文件中指定它们,而不是在AndroidManifest.xml中。
defaultConfig {
    versionCode 1
    versionName "1.0"
}

22
注意,对于多模块项目,在特定模块中查询此内容可能会得到意外的结果。最好将其绑定在主应用程序/活动类的全局命名空间中。 - inder
11
如果您想在库模块中获取有关应用程序的信息,这种方法不起作用。库模块中没有 BuildConfig 文件。 - dumazy
15
@dumazy,库模块可能会有一个 BuildConfig,但你无法获取应用程序的构建信息。你将获得库的信息。 - John Cummings
1
我猜测这个方法返回空字符串的原因是在编写代码时导入了错误的BuildConfig。当我将其粘贴到我的项目中时,我有许多选项可供选择,包括我使用的所有库和模块。我只导入了与自己包名相关联的那个。 - Kaloyan Roussev
3
这个无法与com.android.tools.build:gradle:1.3.0一起工作。 - Kushal
显示剩余4条评论

2205

使用:

try {
    PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
    String version = pInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

你可以使用以下代码获取版本号

int verCode = pInfo.versionCode;

57
@Felix,您不能在上下文之外调用getPackageManager(),因此可能需要使用getApplicationContext()(或传递的上下文)。 - Sver
4
如果您需要在一些静态方法中使用这个数字,而无法传递上下文怎么办?这是我的设计问题吗? - Gubatron
39
不要忘记在调用getPackageInfo()时加上try... catch...语句。 - anticafe
4
我的回答可以静态地获取这些值。 - Sam Dozor
37
如果你只想获取应用程序的版本,直接获取会比较复杂。建议按照这里的建议使用BuildConfig.VERSION_**。请点击链接查看。 - Timo Bähr
显示剩余15条评论

490

如果您只想获取版本名称,则可以使用稍微更短的版本。

try{
    String versionName = context.getPackageManager()
    .getPackageInfo(context.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
        return false;
}

91
好的。这句话可能需要用try/catch语句来捕获NameNotFoundException异常。 - IgorGanapolsky
6
我已经实现了你的解决方案,它运行得很好!但是,如Igor所说,这个解决方案应该被try和catch包围,并且为了调试,将每个方法调用放在单独的一行上而不是在同一行调用context.methodName().subMethod().anotherSubMethod() 等等是一个好的实践。因此,我提供了一个更简洁的解决方案[下面链接中]:https://dev59.com/C2445IYBdhLWcg3w9Ows#18352981 - Michael
2
对于那些使用Gradle的人来说,有一个更简单的解决方案。请查看下面的答案。 - Sam Dozor
1
@Erwinus,我完全不同意使用通用异常来捕获这种情况的观点。更细粒度的异常可以展示开发者对可能出现错误的理解。 - IgorGanapolsky
2
@IgorGanapolsky:这是真的,但如果程序员不理解呢?我认为应用程序的用户不会欣赏任何类型的异常。由于各种各样的Android版本,有可能发生意外情况,如果像这样简单的东西关闭您的应用程序,那将是愚蠢的。如果发生这种情况,您可以假设程序员不了解用户想要什么,因为很容易避免这种情况。此外,如果您想知道出了什么问题,您可以记录异常,其中包含描述。无论是什么类型的异常,未处理的异常都是错误的。 - Codebeat
显示剩余4条评论

210

你需要两个部分:

  • android:versionCode
  • android:versionName

versionCode是一个数字,每次提交到市场的应用版本都需要比上一个版本号更高。

VersionName是一个字符串,可以是任何你想要的。这是你定义应用程序的版本号,如“1.0”、“2.5”、“2 Alpha EXTREME!”等等。

例如:

Kotlin:

val manager = this.packageManager
val info = manager.getPackageInfo(this.packageName, PackageManager.GET_ACTIVITIES)
toast("PackageName = " + info.packageName + "\nVersionCode = "
            + info.versionCode + "\nVersionName = "
            + info.versionName + "\nPermissions = " + info.permissions)

Java:

PackageManager manager = this.getPackageManager();
PackageInfo info = manager.getPackageInfo(this.getPackageName(), PackageManager.GET_ACTIVITIES);
Toast.makeText(this,
     "PackageName = " + info.packageName + "\nVersionCode = "
       + info.versionCode + "\nVersionName = "
       + info.versionName + "\nPermissions = " + info.permissions, Toast.LENGTH_SHORT).show();

6
Android官方对android:versionCodeandroid:versionName的描述可以在这里找到:http://developer.android.com/tools/publishing/versioning.html#appversioning - Goffredo
3
在这种情况下,this 指的是上下文,即活动、服务等。 - Peter Chaula
3
当你粘贴一些示例代码来解释参数的含义很有用......虽然每个人都可以理解this.getPackageName()表示什么,但你刚才放置的0并不知道其含义。 - Rafael Lima
1
Android Studio 声明 versionCode 已过时。 - Roman Gherta
1
@RomanGherta 这是从API 28开始的。如果您使用的是更低版本(或者在8年前写这篇答案时),您仍然可以继续使用。这里还有另一个更新的方法。 - Merkidemis
1
给我一个警告:“versionCode”已被弃用(在Kotlin上)。我应该使用什么代替? - gundrabur

158

使用Gradle和BuildConfig

从BuildConfig获取VERSION_NAME

BuildConfig.VERSION_NAME

没错,现在变得非常容易了。

VERSION_NAME返回一个空字符串吗?

如果你的BuildConfig.VERSION_NAME返回一个空字符串,请继续阅读。

我一直收到BuildConfig.VERSION_NAME返回一个空字符串的情况,因为我没有在我的Gradle构建文件中设置versionName(我从Ant迁移到Gradle)。因此,以下是确保通过Gradle设置VERSION_NAME的说明。

文件build.gradle

def versionMajor = 3
def versionMinor = 0
def versionPatch = 0
def versionBuild = 0 // Bump for dogfood builds, public betas, etc.

android {

  defaultConfig {
    versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild

    versionName "${versionMajor}.${versionMinor}.${versionPatch}"
  }

}

注意:这是来自大师Jake Wharton的。

AndroidManifest.xml中移除versionNameversionCode

由于您现在已经在build.gradle文件中设置了versionNameversionCode,如果它们存在于AndroidManifest.xml文件中,则可以将它们移除。


7
只要您从应用项目中访问BuildConfig,而不是在应用项目中使用的库中访问,它就能很好地工作。否则,您将获取库项目的BuildConfig,而不是应用程序的BuildConfig。 - John Cummings
@JohnCummings 有趣... 没想到那个。 - Joshua Pinter
完全没有反应,versionName "1.2"BuildConfig.VERSION_NAME 返回的是空值。API > 21。 - Sojtin
我曾使用过这个解决方案,但我发现了一个缺陷。如果你有2.6.23版本,然后想要更新到2.7.0版本,那么你得到的versionCode会比较早。因此,我应用了以下公式:versionCode = versionMajor * 10000 + versionMinor * 100 + versionPatch,其中versionPatch的值从0到100。 - 0x131313
2
@JohnCummings 如果你在代码中导入com.package.name.BuildConfig,或者在项目库中进行直接引用的话,它是可以工作的 ;) - SkyzohKey
显示剩余2条评论

61

这是一个基于 scottyab的解决方法(由Xavi编辑)的简洁解决方案。如果您的方法未提供上下文,则它会显示如何首先获取上下文。此外,它使用多行而不是每行调用多个方法。当您需要调试应用程序时,这将使它更容易。

Context context = getApplicationContext(); // or activity.getApplicationContext()
PackageManager packageManager = context.getPackageManager();
String packageName = context.getPackageName();

String myVersionName = "not available"; // initialize String

try {
    myVersionName = packageManager.getPackageInfo(packageName, 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

现在您已经在字符串myVersionName中收到了版本名称,您可以将其设置为TextView或您喜欢的任何内容。

// Set the version name to a TextView
TextView tvVersionName = (TextView) findViewById(R.id.tv_versionName);
tvVersionName.setText(myVersionName);

3
你认为NNFE真的可以被抛弃吗?在软件包管理器中找不到运行的应用程序会很奇怪 :) - TWiStErRob
1
我同意这可能有些奇怪,但这是该方法的默认异常 - 请参见API:它说如果在系统上找不到给定名称的包,则抛出PackageManager.NameNotFoundException。然而,我无法想象出这种情况! - Michael

60

使用以下代码获取应用程序的版本或构建代码,它用于根据其版本代码识别APK文件。版本代码用于在更新、发布等操作时检测实际的构建配置。

int versionCode = BuildConfig.VERSION_CODE;

版本名称用于展示用户或开发者开发顺序。您可以随意添加任何类型的版本名称。

String versionName = BuildConfig.VERSION_NAME;

在所有的答案中,这是最简单的方法。当你可以用一行代码做同样的事情时,为什么要用10多行代码呢?我不理解。 - Amir Dora.

49

Kotlin一行代码

val versionCode = BuildConfig.VERSION_CODE
val versionName = BuildConfig.VERSION_NAME

Java 一行代码

String versionCode = String.valueOf(BuildConfig.VERSION_CODE);
String versionName = String.valueOf(BuildConfig.VERSION_NAME);

请确保在你的类中导入BuildConfig


7
这种方法的缺点是,如果你将这段代码放在一个库模块中,它会显示库的版本而不是应用本身的版本。 - Eugene Krivenja
在这种情况下,OP请求一个Android应用程序,但非常感谢关于库的注释,点赞。 - Gastón Saillén

37

使用BuildConfig类:

String versionName = BuildConfig.VERSION_NAME;
int versionCode = BuildConfig.VERSION_CODE;

文件 build.gradle (应用程序)

defaultConfig {
    applicationId "com.myapp"
    minSdkVersion 19
    targetSdkVersion 27
    versionCode 17
    versionName "1.0"
}

25

截至2020年:自API 28以来(Android 9 (Pie)),“versionCode”已过时,所以我们可以使用“longVersionCode”。

Kotlin示例代码

val manager = context?.packageManager
val info = manager?.getPackageInfo(
    context?.packageName, 0
)

val versionName = info?.versionName
val versionNumber = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                        info?.longVersionCode
                    } else {
                        info?.versionCode
                    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接