Android最低SDK版本与目标SDK版本是什么意思?

482

在开发 Android 应用时,"Min SDK 版本"和 "Target SDK 版本" 有什么区别?如果 Min 和 Target 版本不同,Eclipse 就无法创建新项目!


1
从我所阅读的内容来看,似乎目标 SDK 版本对应用程序的编译没有影响。它只是告诉设备,运行该应用程序时不需要启用任何特殊的兼容性功能,以确保应用程序正常工作。这样说对吗?在我看来,直到编译和进行了大量测试之后,你才会知道你的目标 SDK 版本是什么。为什么编译器不能根据你的代码自动判断应用程序与哪些平台兼容呢? - Michael Novello
5
上面的评论者误解了使用targetSDK功能的原因。请参阅下面我的答案以获得更多详细信息。 - Steve Haley
159
接受的答案不正确。请阅读Steve H.的答案。 - tylerl
3
但这并不是错误,它是在指向Google Android文件。我没有添加任何内容。 - Vikas Patidar
3
我认为Carl的回答是最详细和精确的。 - Ilya Kogan
显示剩余2条评论
9个回答

898

OP在评论中提到的问题(基本上是说targetSDK不影响应用程序的编译)完全是错误的!抱歉直言。

简而言之,声明与minSDK不同的targetSDK的目的是:意味着您正在使用比最低级别更高级别的SDK中的功能,但您已经确保了向后兼容性。换句话说,想象一下,您想使用最近引入的一个功能,但这对您的应用程序并不重要。然后,您将设置targetSDK为引入此新功能的版本,将minimum设置为较低的版本,以便每个人都可以使用您的应用程序。

举个例子,假设您正在编写一个广泛使用手势检测的应用程序。但是,手势可以识别的每个命令也可以通过按钮或菜单完成。在这种情况下,手势是“很棒的额外功能”,但并非必需品。因此,您将将target sdk设置为7(“Eclair”当GestureDetection库被引入时),并将minimumSDK设置为级别3(“Cupcake”),以便即使拥有非常旧的手机的人也可以使用您的应用程序。您只需要确保您的应用程序在尝试使用手势库之前检查其运行的Android版本,以避免在不存在该库时尝试使用它。(诚然,这是一个过时的例子,因为几乎没有人仍然拥有v1.5手机,但是在维护与v1.5的兼容性非常重要的时候曾经存在这样的时候。)

为了举例说明,如果您想要使用Gingerbread或Honeycomb中的某个功能,则可以使用此功能。一些人很快就会得到更新,但许多其他人,尤其是那些使用老旧硬件的人,在购买新设备之前可能会一直停留在Eclair上。这将使您能够使用一些很酷的新功能,但不会排除您可能的部分市场。
有一篇非常好的文章来自Android开发者博客,介绍了如何使用此功能,特别是如何设计我上面提到的“在使用之前检查该功能是否存在”的代码。
对于OP: 我主要是为了未来偶然发现这个问题的任何人的利益而写的,因为我意识到您的问题很久以前就被问过了。

2
请您能否提供一个精确的解释,目标SDK版本如何影响应用程序的编译?因为编译版本是另一个需要设置的配置。先行感谢。 - hnviet
9
我认为Steve混淆了manifest XML属性 android:targetSdkVersion(并没有实际意义)和存储在project.properties文件中的target属性,它代表代码应该编译到哪个版本。我再说一遍,xml属性targetSdkVersion没有实际意义! - AlikElzin-kilaka
3
你的评论有一半是正确的,但另一半则是错误的。我假设某人在XML和project.properties中使用相同的值(也可以通过Eclipse中的右键单击->属性访问),所以你指出它们存储在不同的位置是正确的。然而,Android市场确实关心您在xml属性targetSdkVersion中放置的值。例如,它在确定您是否应该具有Honeycomb及以上应用程序的ActionBar或兼容性菜单时使用该值。 - Steve Haley
2
@Nate 我无法确定这个“复杂代码”会使运行时间变慢多少,但我认为分割和使用多个APK在代码复杂性方面更糟糕。现在你必须记得在源代码控制中注释/取消注释或合并更多分支,然后才能进行每次导出。去年十月份参加Android会议时,他们说他们引入了多个APK系统作为让步,但很少有人使用它,他们感到很高兴。 - Steve Haley
2
但是处理多个版本正是版本控制系统的用途。这是开发人员熟悉的内容(大多数软件,无论是移动还是非移动,都会为不同的平台发布略有不同的版本)。这种 Android “特性”并没有减少复杂性。它只是将其推入运行应用程序中,并且正如本主题所证明的那样,造成了混乱。当然,谷歌很高兴很少有人使用它……这有助于他们说,“看,我们一开始就没有考虑它是正确的”。此外,一些人之所以不使用它,是因为他们还不知道它的存在。 - Nate
显示剩余15条评论

144

android:minSdkVersion

一个整数,表示应用程序运行所需的最低API级别。如果系统的API级别低于此属性中指定的值,则Android系统将阻止用户安装应用程序。您应该始终声明此属性。

android:targetSdkVersion

一个整数,表示应用程序目标API级别。

设置了此属性后,应用程序表示它能够运行在旧版本(至少是minSdkVersion),但已明确测试过与此处指定的版本可以正常工作。指定这个目标版本允许平台禁用不需要为目标版本保持向前兼容性而开启的兼容性设置,或者启用老版本应用程序无法使用的新功能。这并不意味着您可以为平台的不同版本编写不同的功能 - 它仅仅是告知平台您已经针对目标版本进行了测试,平台不应该执行任何额外的工作来保持与目标版本的向前兼容性。

更多信息请参考以下网址:

http://developer.android.com/guide/topics/manifest/uses-sdk-element.html


总的来说,你会将它们都设置为相同的值。将它们设置为不同的值可能是一个不寻常的情况。 - jjb
69
关于jjb的评论:我不同意。你可以有不同的minSDK和targetSDK的很多好理由。请参考我的答案获取更多细节。 - Steve Haley

98
当你设置targetSdkVersion="xx"时,你在确认你的应用程序已经在API级别xx下进行了彻底和成功的测试,并且可以正常工作。一个运行在API水平高于xx的Android版本将自动应用兼容性代码来支持你可能依赖的任何先前可用但现在在该Android版本更高级别上已过时的功能。
相反,如果你正在使用任何在xx级别之前或在xx级别上变得过时的功能,则操作系统版本在更高的API级别上不会自动应用兼容性代码(不再包含这些功能)来支持这些用途。在这种情况下,你自己的代码必须有特殊情况子句来测试API级别,并且如果检测到的操作系统级别是不再具有给定API功能的更高级别,则你的代码必须使用在运行操作系统的API级别上可用的备用功能。
如果没有这样做,则某些界面功能可能根本不会出现,这些功能通常会触发你的代码中的事件,并且你可能会错过用户需要触发这些事件并访问其功能的关键界面功能(如下面的示例所示)。
如其他答案所述,如果你想要使用一些最初在高于minSdkVersion的API级别中定义的API功能,并已经采取措施确保你的代码可以检测和处理低于targetSdkVersion的级别中缺少这些功能,那么你可以将targetSdkVersion设置为高于minSdkVersion。
为了提醒开发者明确测试使用某一特定功能所需的最小API级别,编译器会发出一个错误(而不仅仅是警告),如果代码包含对任何在minSdkVersion之后定义的方法的调用,即使targetSdkVersion大于或等于该方法首次发布的API级别。要消除此错误,请使用编译器指令。
@TargetApi(nn)

使用这个指令可以告诉编译器在调用任何至少需要这个API级别的方法之前,该指令所在范围内的代码已经被编写来测试至少为nn的API级别。例如,以下代码定义了一个方法,可以从具有最低SDK版本小于11且目标SDK版本为11或更高级别的应用程序中调用:

@TargetApi(11)
    public void refreshActionBarIfApi11OrHigher() {
      //If the API is 11 or higher, set up the actionBar and display it
      if(Build.VERSION.SDK_INT >= 11) {
        //ActionBar only exists at API level 11 or higher
        ActionBar actionBar = getActionBar();

        //This should cause onPrepareOptionsMenu() to be called.
        // In versions of the API prior to 11, this only occurred when the user pressed 
        // the dedicated menu button, but at level 11 and above, the action bar is 
        // typically displayed continuously and so you will need to call this
        // each time the options on your menu change.
        invalidateOptionsMenu();

        //Show the bar
        actionBar.show();
    }
}
如果您已经在更高的目标 SDK 版本上测试过且一切运作正常,即使您并未使用高于 minSdkVersion 的 API 级别中的任何功能,可能还需要声明更高的 targetSdkVersion。这只是为了避免访问兼容性代码以从目标级别适应到最小级别的开销,因为您已经通过测试确认不需要进行此类适应。
声明的 targetSdkVersion 可能影响 UI 功能,例如当运行版本高于 11 的 API 时,在状态栏上出现三个竖点菜单按钮的应用程序具有 targetSdkVersion 小于 11。如果您的应用程序的 targetSdkVersion 为10或更低,则假定您的应用程序界面依赖于专用菜单按钮的存在,因此当操作系统具有不再假定设备上具有专用菜单按钮的更高 API 级别(例如在 Gingerbread 中看到的硬件和/或屏幕上早期版本的该按钮)时,三个点会出现以取代此按钮。但是,如果将应用程序的 targetSdkVersion 设置为11或更高,则假定您已经利用了引入的在该级别中替换专用菜单按钮(例如,操作栏)的功能,或者您已经绕过了需要使用系统菜单按钮的需要;因此,三个竖点菜单“兼容性按钮”消失了。在这种情况下,如果用户找不到菜单按钮,则无法按下它,这反过来意味着您的 activity 的 onCreateOptionsMenu(menu) 重写可能永远不会被调用,这又意味着您应用程序功能的重要部分可能无法获得其用户界面。除非您已经实现了操作栏或其他替代方式,让用户访问这些功能。
相比之下,minSdkVersion 表示要运行您的应用程序,设备的操作系统版本必须至少具有该 API 级别。这会影响哪些设备可以在 Google Play 应用商店(以及可能的其他应用商店)上看到和下载您的应用程序。这是一种声明您的应用程序依赖于在该级别确定的操作系统(API 或其他)功能,并且没有一种可接受的方法来处理缺少这些功能。
使用 minSdkVersion 确保存在与 API 无关的功能的示例是将 minSdkVersion 设置为 8,以确保您的应用程序仅在启用 JIT 的 Dalvik 解释器版本上运行(因为 JIT 是在 API 级别 8 引入到 Android 解释器中的)。由于启用 JIT 的解释器的性能可以高达没有该功能的解释器的五倍,如果您的应用程序大量使用处理器,则可能需要要求 API 级别为 8 或更高,以确保足够的性能。

感谢您提供有关使用TargetApi指令的说明。 - samir105
@Carl 这是否意味着我可以将targetSdkVersion始终设置为任何高于我的minSdkVersion的版本(特别是为了获得那些UI增强功能),而无需进行任何测试(本身),只要我限制我的代码库仅使用在我的minSdkVersion中可用的API即可? - Damilola Olowookere
Olowookere Emmanuel:如果我理解你的意思正确的话,那么不,它并不意味着那样。正如我的答案所述,“如果您使用了任何在API级别xx或之前变为过时的功能,则操作系统版本在更高的API级别上不会自动应用兼容性代码。”因此,如果您的代码使用了一个在API级别8可用的功能,并且该功能在级别10变为过时,那么如果您将targetSdkVersion提高到10以上的任何值,将没有兼容性代码可用来调整您对该功能的使用以适应新的操作系统级别。 - Carl
继续上文:如果您将targetSdkVersion保留在8级别,那么虽然您将无法使用在更高级别引入的功能,但会应用兼容性代码以使您对8级别功能的使用在更高的操作系统级别上运行时能够正常工作。 - Carl
延续上文:从这个角度来看:假设您编写的某些代码是在最高可用的Android版本为8时编写的,并且您将targetSdkVersion设置为8(因为那时候是最高级别)。现在,一些新的Android版本发布了,并且您使用的一些级别8功能不再可用。仍然拥有您旧APK的用户不应该出现错误,对吗?因此,为了确保他们不会出现任何问题,兼容性代码会自动应用于调整旧API调用,以便在用户运行更新的OS版本时执行合理操作。 - Carl

52
< p > < strong > < em >通过示例来传递概念总是更好的。 在阅读了Android开发者网站和相关的stackoverflow主题中的所有文档之后,我仍然在理解这些概念方面遇到了困难,直到我深入研究Android框架源代码并进行了一些实验。我会分享两个示例,它们帮助我充分理解这些概念。

基于您在AndroidManifest.xml文件的targetSdkVersion(<uses-sdk android:targetSdkVersion="INTEGER_VALUE"/>)中设置的级别,DatePickerDialog的外观会有所不同。如果您将值设置为10或更低,则您的DatePickerDialog将如左图所示。另一方面,如果您将值设置为11或更高,则DatePickerDialog将看起来像右边的图片,使用完全相同的代码

targetSDKversion 10或更低版本的DatePickerDialog外观 targetSDKversion 11或更高版本的DatePickerDialog外观

我用来创建此示例的代码非常简单。MainActivity.java 如下:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onClickButton(View v) {
        DatePickerDialog d = new DatePickerDialog(this, null, 2014, 5, 4);
        d.show();       
    }
}

而且activity_main.xml看起来像是:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="onClickButton"
    android:text="Button" />
</RelativeLayout>


就是这样。这确实是我需要测试它的所有代码。

当您查看Android框架源代码时,这种外观变化是非常明显的。 它就像这样:

public DatePickerDialog(Context context,
    OnDateSetListener callBack,
    int year,
    int monthOfYear,
    int dayOfMonth,
    boolean yearOptional) {
        this(context, context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB
                ? com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert
                : com.android.internal.R.style.Theme_Dialog_Alert,
        callBack, year, monthOfYear, dayOfMonth, yearOptional);
}

正如您所看到的,该框架获取当前的targetSDKversion并设置不同的主题。在Android框架中,可以随处找到这种代码片段(getApplicationInfo().targetSdkVersion >= SOME_VERSION)。

另一个例子是关于WebView类的。Webview类的公共方法应在主线程上调用,否则,当您设置targetSDKversion为18或更高版本时,运行时系统会抛出RuntimeException。这种行为可以通过其源代码清楚地传达。它就是这样写的。

sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
            Build.VERSION_CODES.JELLY_BEAN_MR2;

if (sEnforceThreadChecking) {
    throw new RuntimeException(throwable);
}

Android文档中指出:“随着每个新版本的推出,一些行为和外观可能会发生变化。” 因此,我们研究了行为和外观的变化以及如何实现这种变化。

总之,Android文档表示:“此属性(targetSdkVersion)通知系统您已针对目标版本进行了测试,并且系统不应启用任何兼容性行为以保持您的应用程序与目标版本的向前兼容性。” 在WebView案例中非常清楚。在JELLY_BEAN_MR2发布之前,可以调用WebView类的公共方法而不会报错。如果Android框架在JELLY_BEAN_MR2设备上抛出RuntimeException,则是无意义的。它只是不应该为其利益启用新引入的行为,这将导致灾难性的结果。因此,我们必须检查某些targetSDKversions上是否一切正常。通过设置更高的targetSDKversion,我们可以获得外观增强等好处,但也需要承担责任。

编辑: 免责声明。 上面展示的基于当前targetSDKversion设置不同主题的DatePickerDialog构造函数实际上已在后续提交中进行了更改。尽管如此,我仍使用了该示例,因为逻辑并未更改,并且这些代码片段清楚地显示了targetSDKversion的概念。


2
我们通过设置更高的targetSDKversion可以获得外观增强等好处,但这也伴随着责任。如果他们在文档中提到了这一行,我就不会寻找它了。 - Manish Kumar Sharma
@김준호 我有两个问题:1.)在上面的日期选择器示例中,如果您将targetSdkVersion设置为10或更低版本,并在运行最新Android(例如API 22)的设备上运行应用程序,日期选择器是否仍会像左侧图片上的旧版本一样显示?2.)这是否意味着我可以始终将targetSdkVersion设置为任何高于我的minSdkVersion的版本(例如,为了获得来自更高API的那些UI增强功能,如脆皮日期选择器),而无需进行任何测试(本身),只要我限制我的代码库仅使用在我的minSdkVersion中可用的API即可? - Damilola Olowookere
想象一种情况,你将最低版本设置为14,目标SDK版本设置为16,并且只使用了14或更低版本的API。比如你使用了在API级别1中引入的TextView。会发生什么? - 김준호
你的第二个例子特别好,因为它展示了一个与接口无关的需求,根据targetSdkVersion进行有选择地执行。 - Carl
在这种情况下,问题不在于调用旧的(或新的)API方法;而是在于从工作线程而不是主线程中调用WebView。在JELLY_BEAN_MR2之前,您可以这样做,但在JELLY_BEAN_MR2之后,这是不允许的。因此,如果您声明您只测试了JELLY_BEAN_MR2之前的targetSdkVersion,他们会防止用户出现错误,因为他们意识到当您的代码在早期版本上进行测试时,您可能不知道需要该行为的新要求。 - Carl
显示剩余4条评论

25

对于那些想要摘要的人,

android:minSdkVersion

这是您的应用程序所支持的最低版本。如果您的设备运行较低版本的Android,则应用程序将无法安装。

然而,

android:targetSdkVersion

API级别是您的应用程序设计运行的最高级别。这意味着,您的手机系统不需要使用任何兼容性行为来保持向前兼容性,因为您已经测试了该API级别。

即使给定的targetSdkVersion低于Android版本,您的应用程序仍将在更高版本的Android上运行,但会触发Android兼容性行为。

额外提供 -

android:maxSdkVersion

如果您的设备API版本更高,则应用程序将无法安装。也就是说,这是您允许应用程序安装的最高API。

例如,对于MinSDK-4、MaxSDK-8、TargetSDK-8,我的应用程序将在最低1.6上工作,但我还使用了仅在2.2上支持的功能,如果安装在2.2设备上,这些功能将可见。此外,对于MaxSDK-8,该应用程序将无法安装在使用API > 8的手机上。

撰写本答案时,Android文档并未很好地解释它。现在它已经非常清楚了。 在此查看


这是错误的。它是您的应用程序继承功能的最小版本 - 即包括您的应用程序使用的所需功能的第一个版本。 - RichieHH
英语是一门棘手的语言。请阅读我在答案中给出的例子。我认为那里我的意思表达得很清楚。 :) - Darpan
我并不是在吹毛求疵,英语是这个群组的支持语言。无论是否棘手,说“最高版本是应用程序支持的版本”不仅是错误的:它完全是180度错误的。它是第一个或最低版本,支持您的应用程序的所有预期功能,而不使用回退兼容模式/库。 - RichieHH

9

如果你遇到一些编译错误,例如:

<uses-sdk
            android:minSdkVersion="10"
            android:targetSdkVersion="15" />

.

private void methodThatRequiresAPI11() {
        BitmapFactory.Options options = new BitmapFactory.Options();
                options.inPreferredConfig = Config.ARGB_8888;  // API Level 1          
                options.inSampleSize = 8;    // API Level 1
                options.inBitmap = bitmap;   // **API Level 11**
        //...
    }

您会遇到编译错误:

字段要求 API 级别 11(当前最小值为 10): android.graphics.BitmapFactory$Options#inBitmap

自 Android 开发工具(ADT)的 17 版本起,有一个新且非常有用的注解 @TargetApi 可以轻松解决此问题。将其添加到包含出现问题声明的方法之前即可:

@TargetApi
private void methodThatRequiresAPI11() {            
  BitmapFactory.Options options = new BitmapFactory.Options();
      options.inPreferredConfig = Config.ARGB_8888;  // API Level 1          
      options.inSampleSize = 8;    // API Level 1

      // This will avoid exception NoSuchFieldError (or NoSuchMethodError) at runtime. 
      if (Integer.valueOf(android.os.Build.VERSION.SDK) >= android.os.Build.VERSION_CODES.HONEYCOMB) {
        options.inBitmap = bitmap;   // **API Level 11**
            //...
      }
    }

现在没有编译错误,并且它将运行!

编辑:这将导致低于11的API级别上运行时错误。在11或更高版本上,它将无问题运行。因此,您必须确保在由版本检查保护的执行路径上调用此方法。TargetApi只允许您进行编译,但自行承担风险。


1
我对此感到困惑。如果您在具有sdk 10的系统中稍后运行应用程序会发生什么? - Fran Marzoa
它将执行options.inBitmap语句,应用程序应该正常工作。 - NinjaCoder

2

android:minSdkVersionandroid:targetSdkVersion都是我们需要在Android清单文件中声明的整数值,但它们具有不同的属性。

android:minSdkVersion:这是运行Android应用程序所需的最低API级别。如果我们将同一应用程序安装在较低的API版本上,则会出现解析器错误,以及应用程序不支持问题。

android:targetSdkVersion:目标SDK版本是设置应用程序的目标API级别。如果在清单中未声明此属性,则minSdk版本将是您的TargetSdk版本。这始终是真实的:“应用程序支持在我们声明为TargetSdk版本的所有更高版本的API上安装”。要使应用程序成为有限目标,我们需要在清单文件中声明maxSdkVersion...


0

如果您正在开发需要危险权限并将targetSDK设置为23或更高版本的应用程序,那么您需要小心谨慎。如果您在运行时不检查权限,则会收到SecurityException异常。例如,如果您在try块中使用打开摄像头的代码,如果不检查logcat,则很难检测错误。


-4

目标 SDK 是您想要针对的版本,而最小 SDK 则是最低版本。


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