Android Min SDK 版本与目标 SDK 版本
Posted
技术标签:
【中文标题】Android Min SDK 版本与目标 SDK 版本【英文标题】:Android Min SDK Version vs. Target SDK Version 【发布时间】:2011-06-01 21:09:30 【问题描述】:在开发android应用时,Min和Target SDK版本有什么区别?除非 Min 和 Target 版本相同,否则 Eclipse 不会让我创建新项目!
【问题讨论】:
从我所读到的,听起来目标 SDK 版本对您的应用程序的编译方式没有影响。它只是告诉设备正在运行应用程序,它不需要启用任何特殊的兼容性功能即可使您的应用程序正常工作。这是正确的吗?在我看来,在您编译并完成大量测试之前,您似乎不知道您的目标 SDK 版本是什么。为什么编译器不能只查看您的代码并自行确定您的应用程序与哪些平台兼容? 上面的评论者误解了为什么要使用targetSDK功能。有关详细信息,请参阅下面的答案。 接受的答案不正确。请阅读 Steve H 的答案。 @tylerl 但这并不是错误的,而是指的是 Google Android 文档。我没有添加任何东西。 卡尔的回答在我看来是最详细和最准确的。 【参考方案1】:OP对该问题的评论(基本上是说targetSDK不影响应用程序的编译)是完全错误的!很抱歉直言不讳。
简而言之,这里是声明与 minSDK 不同的 targetSDK 的目的:这意味着您使用的是比您的最低级别更高级别的 SDK 的功能,但您已确保向后兼容性 。换句话说,假设您想使用最近才引入的功能,但它对您的应用程序并不重要。然后,您可以将 targetSDK 设置为引入此新功能的版本,并将最低版本设置为更低的版本,以便所有人仍然可以使用您的应用。
举个例子,假设您正在编写一个广泛使用手势检测的应用。但是,可以通过手势识别的每个命令也可以通过按钮或菜单来完成。在这种情况下,手势是“很酷的额外”,但不是必需的。因此,您可以将目标 sdk 设置为 7(引入 GestureDetection 库时为“Eclair”),并将 minimumSDK 设置为 3 级(“Cupcake”),这样即使手机非常老旧的人也可以使用您的应用程序。您所要做的就是确保您的应用在尝试使用手势库之前检查了它运行的 Android 版本,以避免在它不存在时尝试使用它。 (诚然,这是一个过时的例子,因为几乎没有人还拥有 v1.5 手机,但曾经有一段时间保持与 v1.5 的兼容性非常重要。)
再举一个例子,如果您想使用 Gingerbread 或 Honeycomb 的功能,可以使用它。有些人会很快得到更新,但许多其他人,尤其是旧硬件,可能会一直坚持使用 Eclair,直到他们购买新设备。这将使您可以使用一些很酷的新功能,但不会排除您可能的市场。
Android developer's blog 有一篇非常好的文章关于如何使用此功能,特别是如何设计我上面提到的“使用前检查该功能是否存在”代码。
致 OP:我写这篇文章主要是为了让将来碰巧遇到这个问题的人受益,因为我知道很久以前就有人问过你的问题。
【讨论】:
能否请您准确解释targetSDKversion如何影响应用程序的编译?因为编译版本又是您需要设置的另一个配置。提前谢谢你 我认为史蒂夫混淆了 manifest xml 属性 android:targetSdkVersion (没有真正的发言权)和驻留在project.properties 文件,它代表应该编译代码的内容。我再说一遍,xml attr targetSdkVersion 没有实际意义!!! @kilaka 你的评论有一半是有效的,但另一半是错误的。我假设有人在 XML 和 project.properties 中使用相同的值(也可以通过 Eclipse 中的右键单击-> 属性访问),因此您正确地指出它们存储在不同的位置。但是,Android Market 最关心的是您在 xml 属性 targetSdkVersion 中设置了什么值。例如,它在确定是否应该为 Honeycomb 及以上应用程序设置 ActionBar 或兼容性菜单时使用它。 @Nate 我不能说这个“复杂的代码”会使运行时慢多少,但我确实认为拆分和使用多个 APK 在代码复杂性方面更糟糕。现在,您必须记住在进行每次导出之前,在源代码管理中通过更多分支进行注释/注释或合并。在去年 10 月的一次 Android 会议上,他们表示他们引入了多 APK 系统作为一种让步,但很高兴很少有人使用它。 但是处理多个版本是版本控制系统的目的。这是开发人员所熟悉的(大多数软件,无论是否移动,都会针对不同平台发布略有不同的版本)。这个Android“功能”并没有降低复杂性。它只是将其推送到正在运行的应用程序中,正如这个线程所证明的那样,造成了混乱。当然,谷歌会很高兴很少有人使用它……这有助于他们说,“看,我们一开始就忽略了这个问题”。另外,有些人不使用它是因为他们还不知道它的存在。【参考方案2】:android:minSdkVersion
一个整数,指定应用程序运行所需的最低 API 级别。如果系统的 API Level 低于此属性中指定的值,Android 系统将阻止用户安装应用程序。您应该始终声明此属性。
android:targetSdkVersion
一个整数,指定应用程序所针对的 API 级别。
使用此属性集,应用程序表示它能够在旧版本上运行(低至 minSdkVersion),但经过明确测试可以与此处指定的版本一起使用。指定此目标版本允许平台禁用目标版本不需要的兼容性设置(否则可能会打开以保持向前兼容性)或启用旧应用程序不可用的新功能。这并不意味着您可以为平台的不同版本编写不同的功能——它只是通知平台您已经针对目标版本进行了测试,并且平台不应该执行任何额外的工作来保持与目标版本的前向兼容性。
更多信息请参考这个网址:
http://developer.android.com/guide/topics/manifest/uses-sdk-element.html
【讨论】:
总的来说,您要将两者设置为相同的内容。将它们设置为不同的值可能是一种不寻常的情况。 关于 jjb 的评论:我不同意。您可以使用不同的 minSDK 和 targetSDK 有很多很好的理由。有关详细信息,请参阅我的答案。【参考方案3】:当您设置 targetSdkVersion="xx" 时,您正在证明您的应用在 API 级别 xx 上可以正常运行(例如,已经过彻底和成功的测试)。
在 API 级别 xx 运行的 Android 版本将自动应用兼容性代码,以支持您可能依赖的任何功能,这些功能在 API 级别 xx 或之前可用,但现在在该 Android 版本的更高级别已过时。
相反,如果您使用的任何功能在或在级别 xx 之前已过时,兼容性代码将不会自动应用更高 API 级别的操作系统版本(不再包含这些功能)以支持这些用途。在这种情况下,您自己的代码必须具有测试 API 级别的特殊情况子句,并且如果检测到的操作系统级别更高,不再具有给定 API 功能,您的代码必须使用 的替代功能em> 在正在运行的操作系统的 API 级别可用。
如果未能做到这一点,那么某些通常会在您的代码中触发事件的界面功能可能根本不会出现,并且您可能缺少用户需要触发这些事件并访问其功能的关键界面功能(如下例所示)。
如其他答案中所述,如果您想使用最初在比您的 minSdkVersion 更高的 API 级别定义的某些 API 功能,并且已采取措施确保您的代码可以检测和处理没有那些低于 targetSdkVersion 的功能。
为了警告开发人员专门测试使用某个功能所需的最低 API 级别,如果代码包含对在更高 API 级别定义的任何方法的调用,编译器将发出错误(不仅仅是警告)比 minSdkVersion,即使 targetSdkVersion 大于或等于该方法首次可用的 API 级别。为了消除这个错误,编译器指令
@TargetApi(nn)
告诉编译器该指令范围内的代码(将在方法或类之前)已被编写用于在调用任何依赖于至少 nn 的方法之前测试 API 级别至少为 nn该 API 级别。例如,以下代码定义了一个可以从 minSdkVersion 小于 11 且 targetSdkVersion 为 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();
您可能还想要声明更高的 targetSdkVersion,如果您已经在更高级别进行了测试并且一切正常,即使您没有使用 API 级别的任何功能高于你的 minSdkVersion。这只是为了避免访问旨在从目标级别向下调整到最低级别的兼容性代码的开销,因为您会(通过测试)确认不需要这样的调整。
依赖于声明的 targetSdkVersion 的 UI 功能的一个示例是在 targetSdkVersion 小于 11 的应用程序在 API 11 或更高版本下运行时显示在状态栏上的三个垂直点菜单按钮.如果您的应用程序的 targetSdkVersion 为 10 或更低,则假定您的应用程序界面取决于专用菜单按钮的存在,因此三点按钮似乎取代了早期的专用硬件和/或屏幕版本当操作系统具有更高的 API 级别时,不再假定设备上的专用菜单按钮为该按钮(例如,如在 Gingerbread 中所见)。但是,如果您将应用程序的 targetSdkVersion 设置为 11 或更高,则假定您已经利用了在该级别引入的替代专用菜单按钮(例如操作栏)的功能,或者您已经规避了需要有一个系统菜单按钮;因此,三竖点菜单“兼容性按钮”消失了。在这种情况下,如果用户找不到菜单按钮,她就无法按下它,这反过来意味着您的活动的 onCreateOptionsMenu(menu) 覆盖可能永远不会被调用,这又意味着您的应用程序功能的很大一部分可能会被剥夺其用户界面。当然,除非您实现了操作栏或其他一些可供用户访问这些功能的替代方式。
相比之下,minSdkVersion 要求设备的操作系统版本至少具有该 API 级别才能运行您的应用。这会影响哪些设备能够在 Google Play 应用商店(可能还有其他应用商店)上查看和下载您的应用。这是一种说明您的应用依赖于在该级别建立的操作系统(API 或其他)功能的方式,并且没有可接受的方式来处理这些功能的缺失。
使用 minSdkVersion 来确保存在 不 API 相关的功能的示例是将 minSdkVersion 设置为 8 以确保您的应用仅在启用 JIT 的情况下运行Dalvik 解释器的版本(因为 JIT 在 API 级别 8 被引入 Android 解释器)。由于启用 JIT 的解释器的性能可能是缺少该功能的解释器的五倍,因此如果您的应用大量使用处理器,那么您可能需要 API 级别 8 或更高以确保足够的性能。
【讨论】:
感谢使用 TargetApi 指令的说明。 @Carl 这是否意味着我可以随时将 targetSdkVersion 设置为高于我的 minSdkVersion 的任何版本(尤其是为了获得那些 UI 增强功能)而无需任何测试(本身)只要我限制我的代码库只使用我的 minSdkVersion 中可用的 API? Olowookere Emmanuel:如果我理解正确,那么不,不是那个意思。正如我的回答所说,“如果您使用的任何功能在 xx 级别或之前已过时,则更高 API 级别的操作系统版本不会自动应用兼容性代码。”因此,如果您的代码使用的功能在 API 级别 8 时可用,并且该功能在级别 10 时已过时,那么如果您将 targetSdkVersion 提高到 10 以上的任何值,将没有可用于调整您使用的兼容性代码将该功能升级到新的操作系统级别。 (继续):然而,如果您将 targetSdkVersion 保留在级别 8,那么,虽然您将无法使用更高级别引入的功能,但将应用兼容性代码以允许您使用在更高的操作系统级别上运行时可以使用 8 级功能。 (继续):这样想:假设您在可用的最高 Android 级别为 8 时编写了一些代码,并且您将 targetSdkVersion 设置为 8(因为那是当时的***别)。现在,一些新版本的 Android 发布了,您使用的一些 8 级功能变得不可用。仍然拥有旧 APK 的用户应该不会遇到错误,不是吗?因此,为确保它们不会发生这种情况,兼容性代码会自动应用以调整旧 API 调用,以便在用户运行更新版本的操作系统时调用它们时执行一些合理的操作。【参考方案4】:总是可以通过示例更好地传达概念。在我深入研究 Android 框架源代码并进行一些实验之前,我很难理解这些概念,即使在阅读了 Android 开发人员网站和相关 *** 线程中的所有文档之后也是如此。我将分享两个对我全面理解这些概念有很大帮助的例子。
根据您在 AndroidManifest.xml 文件的 targetSDKversion(<uses-sdk android:targetSdkVersion="INTEGER_VALUE"/>
) 中放置的级别,DatePickerDialog 看起来会有所不同。如果您将值设置为 10 或更低,您的 DatePickerDialog 将看起来像左边。另一方面,如果您将值设置为 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_
android:layout_ >
<Button
android:layout_
android:layout_
android:onClick="onClickButton"
android:text="Button" />
</RelativeLayout>
而已。这确实是我需要测试的所有代码。
当您看到Android framework source code 时,这种外观变化非常明显。它是这样的:
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 并设置不同的主题。这种代码 sn-p(getApplicationInfo().targetSdkVersion >= SOME_VERSION
) 在 Android 框架中随处可见。
另一个例子是关于WebView 类。 Webview 类的公共方法应该在主线程上调用,如果没有,运行时系统会在您设置 targetSDKversion 18 或更高版本时抛出RuntimeException
。使用its source code 可以清楚地传达此行为。就是这么写的。
sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
Build.VERSION_CODES.JELLY_BEAN_MR2;
if (sEnforceThreadChecking)
throw new RuntimeException(throwable);
The Android doc 说:“随着每个新版本的 Android 不断发展,某些行为甚至外观可能会发生变化。”所以,我们已经研究了行为和外观的变化,以及这种变化是如何完成的。
总而言之,Android 文档说“此属性 (targetSdkVersion) 通知系统您已针对目标版本进行了测试,并且系统不应启用任何兼容性行为以维护您应用的与目标版本的前向兼容性。”。这在 WebView 案例中非常清楚。在 JELLY_BEAN_MR2 发布之前可以在非主线程上调用 WebView 类的公共方法。如果 Android 框架在 JELLY_BEAN_MR2 设备上抛出 RuntimeException 是无稽之谈。它只是不应该为了它的利益而启用新引入的行为,这会导致致命的结果。因此,我们要做的是检查某些 targetSDK 版本是否一切正常。我们可以通过设置更高的 targetSDKversion 获得外观增强等好处,但它是有责任的。
编辑: 免责声明。基于当前 targetSDKversion(我在上面展示的)设置不同主题的 DatePickerDialog 构造函数实际上已在 later commit 中更改。不过我还是用了那个例子,因为逻辑没有改变,而且那些代码sn-p清楚地显示了targetSDKversion的概念。
【讨论】:
"我们可以通过设置更高的 targetSDK 版本获得外观增强等好处,但它伴随着责任。"如果他们在文档中提到了这一行,我就不会去找它了。 @김준호 我有两个问题: 1.)在上面的 datepicker 示例中,如果您将 targetSdkVersion 设置为 10 或更低,并在运行最新 Android(例如 API 22)的设备上运行应用程序将日期选择器仍然像左边图片中的旧一样显示? 2.) 这是否意味着我总是可以将 targetSdkVersion 设置为高于我的 minSdkVersion 的任何版本(例如,从更高的 API 中获得诸如脆日期选择器之类的 UI 增强功能)而无需任何测试(本身)只要我限制我的代码库只使用我的 minSdkVersion 中可用的 API? @Olowookere 1) 是的。就跑吧。 2)如果targetSDKVersion高于minSDKVersion,您可以设置任何您喜欢的版本。但是您仍然需要测试它在目标版本上是否可以正常工作。不管你是否坚持使用 minSDKVersion api。想想 DatePicker 的例子。 想象一下你设置最低版本 14 & target sdk 版本为 16 的情况,而你只使用了 14 或更低版本的 api。假设您使用了 API 级别 1 中引入的 TextView。会发生什么? @김준호 谢谢。但是对于你的第二个答案,我很困惑。如果我的代码仅使用 minSdkVersion 中的 API 并且我针对更高版本的 SDK,我为什么需要测试?想想 DatePicker 的例子,高 targetSdkVersion 只改善了 DatePicker 小部件的外观,没有任何问题,因为我没有在 API 中使用任何高于 minSdkVersion 的代码。我只想要更高的 targetSdkVersion,因为我想要小部件的新外观,而不是我想要使用更高 API 中引入的新功能【参考方案5】:对于那些想要总结的人,
android:minSdkVersion
在您的应用程序支持之前是最低版本。如果您的设备的 android 版本较低,应用将无法安装。
同时,
android:targetSdkVersion
是您的应用设计运行的 API 级别。意味着,您的手机系统不需要使用任何兼容性行为来保持前向兼容性,因为您已经针对此 API 进行了测试。
您的应用仍将在高于给定 targetSdkVersion
的 Android 版本上运行,但 Android 兼容性行为将会启动。
免费赠品 -
android:maxSdkVersion
如果您设备的 API 版本较高,应用将无法安装。 IE。这是您允许安装应用的最大 API。
即。对于 MinSDK -4、maxSDK - 8、targetSDK - 8 我的应用程序将在最低 1.6 上运行,但我也使用了仅在 2.2 中支持的功能,如果它安装在 2.2 设备上将可见。此外,对于 maxSDK - 8,此应用不会安装在 API > 8 的手机上。
在撰写此答案时,Android 文档在解释它方面做得并不好。现在解释得很好。 Check it here
【讨论】:
'是您的应用继承功能的最高版本。' : 这是错误的。它是您的应用继承功能的最低版本 - 即包含您的应用使用的所需功能的第一个版本。 英语是一种棘手的语言。阅读我在答案中给出的示例。我认为我在那里说得通。 :) 我不是迂腐的,英语是这个小组的支持语言。棘手或不说它是“应用程序支持功能的最大版本”不仅是错误的:它完全错了 180 度。它是第一个或最低版本,它支持您的应用程序的所有预期功能,而无需使用回退兼容模式/库。【参考方案6】:如果你得到一些编译错误,例如:
<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**
//...
现在没有编译错误它会运行!
编辑:这将导致 API 级别低于 11 的运行时错误。在 11 或更高级别上,它将毫无问题地运行。因此,您必须确保在受版本检查保护的执行路径上调用此方法。 TargetApi 只允许您编译它,但运行它需要您自担风险。
【讨论】:
我对此感到困惑。如果您稍后在具有 sdk 10 的系统中运行您的应用程序会发生什么? 它将执行 options.inBitmap 语句并且应用程序应该可以正常工作。【参考方案7】:android:minSdkVersion
和 android:targetSdkVersion
都是整数值,我们需要在 android 清单文件中声明,但它们具有不同的属性。
android:minSdkVersion:
这是运行 Android 应用所需的最低 API 级别。如果我们在较低的 API 版本上安装相同的应用程序,则会出现解析器错误,并且会出现应用程序不支持问题。
android:targetSdkVersion:
Target sdk version 设置应用的 Target API 级别。如果此属性未在清单中声明,则 minSdk 版本将是您的 TargetSdk 版本。 “应用程序支持在我们声明为 TargetSdk 版本的所有更高版本的 API 上安装”始终是正确的。为了使应用受限目标,我们需要在清单文件中声明 maxSdkVersion...
【讨论】:
【参考方案8】:如果您正在制作需要dangerous permissions 并将targetSDK 设置为23 或更高版本的应用程序,您应该小心。如果你不在运行时检查权限,你会得到一个 SecurityException,如果你在 try 块中使用代码,例如打开相机,如果你不检查 logcat,就很难检测到错误。
【讨论】:
【参考方案9】:target sdk 是你要定位的版本,min sdk 是最低版本。
【讨论】:
以上是关于Android Min SDK 版本与目标 SDK 版本的主要内容,如果未能解决你的问题,请参考以下文章
以 Android SDK 版本 29 为目标后,读取/写入下载文件夹被拒绝
FFMPEG命令在设置项目的目标SDK版本29(Android Q问题)时不起作用