应用不支持android版本

2016-04-27 14:47:06 liao277218962 阅读数 9834

FROM:http://www.cnblogs.com/yaowen/p/5013366.html

在Android系统中向下兼容性比较差,但是一个应用APP经过处理还是可以在各个版本间运行的。向下兼容性不好,不同版本的系统其API版本也不同,自然有些接口也不同,新的平台不能使用旧的API,旧的平台也使用不了新的API。

        为了应用APP有更好的兼容性,咱们可以利用高版本的SDK开发应用,并在程序运行时(Runtime)对应用所运行的平台判断,旧平台使用旧的API,而新平台可使用新的API,这样可以较好的提高软件兼容性。

 

        那么,如何在软件运行时做出这样的判断呢?答案下边揭晓:

 

  在Android SDK开发文档中有段话这样的话:

Check System Version at Runtime(在软件运行时检查判断系统版本)


Android provides a unique code for each platform version in the Build constants class. Use these codes within your app to build conditions that ensure the code thatdepends on higher API levels is executed only when those APIs are available on the system.

private void setUpActionBar() {
    // Make sure we're running on Honeycomb or higher to use ActionBar APIs
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

         ActionBar actionBar = getActionBar();
         actionBar.setDisplayHomeAsUpEnabled(true);
    }
}

Note: When parsing XML resources, Android ignores XML attributes that aren’t supported by the current device. So you can safely use XML attributes thatare only supported by newer versions without worrying about older versions breaking when theyencounter that code. For example, if you set the targetSdkVersion="11", your app includes the ActionBar by defaulton Android 3.0 and higher. To then add menu items to the action bar, you need to set android:showAsAction="ifRoom" in your menu resource XML. It's safe to do this in a cross-version XML file, because the older versions of Android simply ignore the showAsAction attribute (that is, you do not need a separate version in res/menu-v11/).

 

           从上面可以知道Android为我们提供了一个常量类Build,其中最主要是Build中的两个内部类VERSION和VERSION_CODES,

VERSION表示当前系统版本的信息,其中就包括SDK的版本信息,用于成员SDK_INT表示;

对于VERSION_CODES在SDK开发文档中时这样描述的,Enumeration of the currently known SDK version codes. These are the values that can be found in SDK. Version numbers increment monotonically with each official platform release.

其成员就是一些从最早版本开始到当前运行的系统的一些版本号常量。

  在我们自己开发应用过程中,常常使用如下的代码形式判断运行新API还是旧的API:

 


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 
    {
            // 包含新API的代码块
    }
    else
    {
            // 包含旧的API的代码块
    }


     OK,大家都知道原理了吧! 需要实例的百度蛮多的,这里就不提供了。

 

 

 

android 10(2.2.3/2.2.4)及以下的版本是没有fragment的,从 11(3.0.x) 就有了,这就是新特性,诸如此类的还有很多呢。

不明白题主的“向下兼容”具体指哪方面,就我理解的来说吧:

为了使老版本的sdk能用上新版本的特性和功能,官方都会给出额外的jar包,还是以 fragment 为例,如果我开发的app必须要能在 2.3的系统上运行,但同时要使用 fragment 怎么办呢?此时就可以用引入android.support.v4.jar包,这就是官方给的兼容性解决方案了。

可以发现,随着 SDK 版本的不断升级,官方给出的jar包也越来越多,android.support.v7.jar,v13......

如果你想详细了解下某些版本的升级带来了哪些新特性,欢迎访问Android 5.0 Behavior Changes,当然,感兴趣的话也可以找到历史版本的升级记录,在这里就不多说了。。。

 

 

 

Android 版本更替,新的版本带来新的特性,新的方法。

新的方法带来许多便利,但无法在低版本系统上运行,如果兼容性处理不恰当,APP在低版本系统上,运行时将会crash。

本文以一个具体的例子说明如何在使用高API level的方法时处理好兼容性问题。

例子:根据给出路径,获取此路径所在分区的总空间大小。

安卓中的文件存储使用参考中提到:

获取文件系统用量情况,在API level 9及其以上的系统,可直接调用File对象的相关方法,以下需自行计算

一般实现

就此需求而言,API level 9及其以上,调用 File.getTotalSpace() 即可, 但是在API level 8 以下系统File对象并不存在此方法。

如以下方法:

/**
 * Returns the total size in bytes of the partition containing this path.
 * Returns 0 if this path does not exist.
 * 
 * @param path
 * @return -1 means path is null, 0 means path is not exist.
 */
public static long getTotalSpace(File path) {
    if (path == null) {
        return -1;
    }
    return path.getTotalSpace();
}
处理无法编译通过

如果minSdkVersion设置为8,那么build时候会报以下错误:

Call requires API level 9 (current min is 8)

为了编译可以通过,可以添加 @SuppressLint("NewApi") 或者 @TargeApi(9)

@TargeApi($API_LEVEL)显式表明方法的API level要求,而不是@SuppressLint("NewApi");

但是这样只是能编译通过,到了API level8的系统运行,将会引发 java.lang.NoSuchMethodError

正确的做法

为了运行时不报错, 需要:

  1. 判断运行时版本,在低版本系统不调用此方法
  2. 同时为了保证功能的完整性,需要提供低版本功能实现

    如下:

    /**
     * Returns the total size in bytes of the partition containing this path.
     * Returns 0 if this path does not exist.
     * 
     * @param path
     * @return -1 means path is null, 0 means path is not exist.
     */
    @TargetApi(Build.VERSION_CODES.GINGERBREAD) 
        // using @TargeApi instead of @SuppressLint("NewApi")
    @SuppressWarnings("deprecation")
    public static long getTotalSpace(File path) {
        if (path == null) {
            return -1;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            return path.getTotalSpace();
        }
        // implements getTotalSpace() in API lower than GINGERBREAD
        else {
            if (!path.exists()) {
                return 0;
            } else {
                final StatFs stats = new StatFs(path.getPath());
                // Using deprecated method in low API level system, 
                // add @SuppressWarnings("description") to suppress the warning
                return (long) stats.getBlockSize() * (long) stats.getBlockCount();
            }
        }
    }
    

总结

在使用高于minSdkVersion API level的方法需要:

  1. @TargeApi($API_LEVEL) 使可以编译通过, 不建议使用@SuppressLint("NewApi");
  2. 运行时判断API level; 仅在足够高,有此方法的API level系统中,调用此方法;
  3. 保证功能完整性,保证低API版本通过其他方法提供功能实现。

 

 

 

Android 开发之API兼容问题

问题背景

鉴于ANDROID SDK 更新较快,很多新的特性和API在低版本中的可能没有。所以开发过程中尽量要保持对新功能接口的兼容。

一般开发过程中APP都会有一个最低版本的配置,例如如果要兼容到android 2.2系统,则可以设置minSdkVersion=8,这就表明能向下兼容到android 2.2版本,即APP能在android2.2版本上的手机也能正常运行,即使可能某些新特性的功能支持失效,但至少保证不会出现崩溃的问题,而避免此问题的方式就要求开发者在代码中做好兼容和适配。

 

兼容原则

一般选择APP的最低支持版本原则是尽量向下保持兼容,但也不是说越向下越好,主要的考虑因素有以下几点:

1.      各个低版本手机的市场占有率,比如2013年android 2.2的手机还占用一定的市场份额,但到现在为止基本上该份额可以忽略不计了(目前android 最高的版本已达到android 5.1了)

2.      APP的针对用户群体,比如是高端的用户群体,屌丝用户群体,还是中低端用户群体,根据不同的用户群体可以综合出来决定对最低版本的支持。

基于SDK高低开发优缺点

基于低版本的SDK开发

优点就是你可以支持的手机用户会更多,基本上各个版本的用户都可以用你的应用。

但缺点也是非常明显,特别是对开发者来说,需要做好每一个新特性功能的适配和开发,随着版本越来越高,这对开发者后期的维护会越来越困难,越来越多。

基于高版本的SDK开发

如果你用最新的版本的SDK, 优点就是你可以使用最新的功能的api,而且编译也不会出现任何问题。

但是缺点就是你需要时刻对你调用的api保持向下兼容性,因为很有可能你现有调用的某个api在低版本中根本就不存在。这时候你需要考虑低版本系统的用户的运行问题了。

 

 

实战分析

如某个工程配置中的最低版本是android2.2,也就是正常来说开发过程中需要基于android SDK为8来做工程开发。但如果你没有基于adroid  2.2 SDK版本开发,而是支持了一个更高的版本,比如android 4.0 SDK开发,那么很多高版本的功能特性(2.3—4.0)在4.0以下的手机中运行就可以存在问题,一般的结果就是直接crash。

下面是基于android2.2 SDK 开发环境编译的最新的工程,其中就有一些直接编译运行不过的错误。下面可以看几个实例:

SampleActivity.java有一处这样写的:

      if (savedInstanceState !=null) {

         mOrderId =savedInstanceState.getString(EXTRA_ORDER_ID);

         mPaySuccess =savedInstanceState.getString(EXTRA_PAY_SUCCESS,"");

      }

代码中使用Bundle对象在新版本中才提供的方法而没有加兼容处理,如下官方文档中解释,该方法在android 3.1后才有。

public String getString (String key, String defaultValue) Added in API level 12

如果在低于android 3.0下机器运行和编译该代码,如果不做任何处理,会直接编译通不过。

 

解决方法:

1.       用android提供的注解 @TargetApi(11)+ 版本号控制做兼容

如果是基于高版本的SDK开发,则新的api肯定会有该方法,如果想让编译的版本在低版本中也能运行,则需要考虑到版本兼容的问题,可以用如下的方式:

/***

     * 该api版本兼容获取指定参数

     *

     * @param savedInstanceState

     * @return

     */

   @TargetApi(12)

   privateString getPaySucess(Bundle savedInstanceState) {

        if (Build.VERSION.SDK_INT >= 12) {

            mPaySuccess = savedInstanceState.getString(EXTRA_PAY_SUCCESS,"");

        } else {

            mPaySuccess = savedInstanceState.getString(EXTRA_PAY_SUCCESS);

            if (mPaySuccess ==null){

                mPaySuccess = "";

            }

        }

        returnmPaySuccess;

}

 

2.       用反射的方式调用高版本中的新功能接口进行调用。

如果是基于低版本SDK开发,那么新版本中的新接口肯定会编译不过,这时候可以考虑反射的方式先去查找是否存在这个方法,如果有就代表用户的手机支持该调用方法,如果没有则采用低版本的处理方式。

 

   /***

     * 通过放射的方式来获取Bundle中的

     * getString(String key,String value)方法

     *

     * @return

     */

   privateStringgetPaySucessInvoke(Bundle savedInstanceState) {

 

        try {

            Class<?> c = Class.forName("android.os.bundle");

            Method mGetString2Params =c.getDeclaredMethod("getString", String.class,String.class);

 

            if (mGetString2Params !=null) {

                mPaySuccess = (String)mGetString2Params.invoke(null,EXTRA_PAY_SUCCESS,"");

            } else {

                mPaySuccess = savedInstanceState.getString(EXTRA_PAY_SUCCESS);

                if (mPaySuccess ==null){

                    mPaySuccess ="";

                }

            }

        } catch (Exception e) {

            // TODO: handle exception

        }

 

        returnmPaySuccess;

    }

 

3.       分离代码,分别在不同的SDK上编译运行,最后ClassLoader动态加载高版本中的相关类接口

此方法应用场景如2,可以将高版本的api接口封装后在高版本的SDK中编译运行jar包,供旧版本的工程中动态加载。

SDK相关对应表

Platform Version

API Level

VERSION_CODE

Notes

Android 5.1

22

LOLLIPOP_MR1

Platform Highlights

Android 5.0

21

LOLLIPOP

Android 4.4W

20

KITKAT_WATCH

KitKat for Wearables Only

Android 4.4

19

KITKAT

Platform Highlights

Android 4.3

18

JELLY_BEAN_MR2

Platform Highlights

Android 4.2, 4.2.2

17

JELLY_BEAN_MR1

Platform Highlights

Android 4.1, 4.1.1

16

JELLY_BEAN

Platform Highlights

Android 4.0.3, 4.0.4

15

ICE_CREAM_SANDWICH_MR1

Platform Highlights

Android 4.0, 4.0.1, 4.0.2

14

ICE_CREAM_SANDWICH

Android 3.2

13

HONEYCOMB_MR2

Android 3.1.x

12

HONEYCOMB_MR1

Platform Highlights

Android 3.0.x

11

HONEYCOMB

Platform Highlights

Android 2.3.4
Android 2.3.3

10

GINGERBREAD_MR1

Platform Highlights

Android 2.3.2
Android 2.3.1
Android 2.3

9

GINGERBREAD

Android 2.2.x

8

FROYO

Platform Highlights

Android 2.1.x

7

ECLAIR_MR1

Platform Highlights

Android 2.0.1

6

ECLAIR_0_1

Android 2.0

5

ECLAIR

Android 1.6

4

DONUT

Platform Highlights

Android 1.5

3

CUPCAKE

Platform Highlights

Android 1.1

2

BASE_1_1

Android 1.0

1

BASE

 

参考:

http://developer.android.com/reference/packages.html

2014-10-09 11:31:55 huiguixian 阅读数 15105

如果有一个apk,需要知道他最低安装支持的Android版本是什么,应该如何查看呢?

直接将apk后缀名改为rar或者zip,拉出AndroidManifest.xml?不行,AndroidManifest.xml已经被编译过了,里面很多内容改为二进制了。

其实用Android自带工具即可,进入Android SDK目录。

cd sdk\build-tools\android-4.4.2 这边以4.4.2为例,可以参照自己的platform版本

aapt.exe list -a someapk.apk > apkversion.txt

然后用记事本之类的应用打开apkversion.txt搜索

minSdkVersion,以我这边为例,可以看到这便是0xf,即15

    E: uses-sdk (line=8)
      A: android:minSdkVersion(0x0101020c)=(type 0x10)0xf


15对应的Android版本可以从这边查阅:

Android版本和API Level对应关系

2014-11-19 12:58:27 y150481863 阅读数 13117

转载请注明出处【http://blog.csdn.net/y150481863/article/details/41280045

首先我们在开发一个应用之前,特别是一个android应用,首先要考虑这个系统是运行在android版本为2.3的系统上,还是4.0的系统上或者说是支持所有android版本的系统。

有了这样的决定之后,接下来我们就需要做点事了,需要告诉系统你当前应用所能兼容的系统版本是多少,从而系统决定是否能有效并成功安装你的应用。

这就是android project中Manifest.xml中的<uses-sdk>标签元素决定的。

此标签包含如下3个属性:

android:minSdkVersion —— 此属性决定你的应用能兼容的最低的系统版本,一盘情况是必须设置此属性。

android:targetSdkVersion —— 此属性说明你当前的应用是针对某一个系统版本开发设计的,也就是说在这个系统版本上运行是没有任何问题的。对于手机或其他终端设备会根据此属性值,决定是否显示一些特性和效果。当然对于开发者最直接的影响就是,你所用到的API都是基于此版本上的,高于此targetSdkVersion的API在使用的时候会有警告或者错误提示。

android:maxSdkVersion ——  此属性是决定你的应用能支持的版本最高是多少,超过此版本的系统将不能使用你的应用。


sdkversion


比如以上代码中能支持的最低系统的版本号是10,使用的是版本号为16的系统API。

对于大家经常交流的手机是android2.3的系统或者4.0的系统,还是刚出来的5.0的系统;这里的2.3、4.0、5.0都只是版本名称。版本名称4.0对应版本号(API LEVEL)是14。

版本名称和版本号的介绍可以看此文章:http://blog.csdn.net/y150481863/article/details/41249159


此知识点可能不是什么大问题,记录仅仅作为刚入门的人了解。



2017-01-06 21:41:53 han1202012 阅读数 3893

初学者遇到 Android Studio, 导入工程后, 会出现各种奇葩错误, 如果管理好各个插件, gradle, SDK, SDK Tools, 各种官方依赖库 的版本, 会将错误大大的减少;

这里将常用的 Android Studio 常用的 相关版本 总结下.



相关网站

-- Android中support库的版本 : http://blog.liudonghua.com/?p=326;

-- 官方文档 : https://developer.android.com/topic/libraries/support-library/features.html;

-- AS 官网 : https://sites.google.com/a/android.com/tools/;

-- Android 官网 AS 页面 : https://developer.android.com/studio/index.html;

-- 查询最新的 Gradle 版本网站 : https://services.gradle.org/distributions/;

-- 查询最新的 Gradle 插件版本 : https://jcenter.bintray.com/com/android/tools/build/gradle/;




1. Android Studio 版本



AS (Android Studio) 相关网站

-- AS 官网 : https://sites.google.com/a/android.com/tools/;

-- Android 官网 AS 页面 : https://developer.android.com/studio/index.html;


版本介绍

-- Canary (金丝雀) : 每周都更新, 功能最多的版本.

-- Dev (开发版) : 金丝雀版 经过完整测试后, 升级为 开发版;

-- Beta : 发布基于稳定的金丝雀版本, 该版本与一个稳定版本一起更新, 直到下一个稳定版本更新;

-- Stable (稳定版) : 当前开发最稳定的版本, Android 开发者官网推荐版本;

-- 版本升级顺序 : 金丝雀版 -> 开发版 -> Beta 版 -> 稳定版;



Android Studio 版本管理

-- 查看当前的 AS 版本 : 菜单栏 Help -> About, 弹出如下对话框;


-- 更新检查 : 菜单 Help -> Check for Update, 在弹出的对话框, 查看最新版本;


-- 检查更新来源设置 : 点击 Update Info 中的 蓝色的 Updates 链接, 即可在弹出的对话框中设置更新来源, 这里我们选择稳定版本;







2. Gradle 版本




Gradle 版本

-- 查询最新的 Gradle 版本网站 : https://services.gradle.org/distributions/;


-- 设置最新的 Gradle 版本 : 工程根目录/gradle/wrapper/gradle-wrapper.properties 中设置 distributionUrl 属性, 如下 : 

distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip



注意 : Gradle 版本, Gradle 插件版本, SDK Build Tools 版本是相关的, 如果三个版本不兼容, 会出现各种错误, 这里建议都安装最新版本的;





3. Gradle 插件 版本



Gradle 插件版本

-- 查询最新的 Gradle 插件版本 : https://jcenter.bintray.com/com/android/tools/build/gradle/;

-- 设置最新的 Gradle 插件版本 : 工程根目录/build.gradle 中进行如下设置;

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
    }
}


注意 : Gradle 版本, Gradle 插件版本, SDK Build Tools 版本是相关的, 如果三个版本不兼容, 会出现各种错误, 这里建议都安装最新版本的;



4. SDK Build Tools 版本




SDK Build Tools 版本

-- 查询最新的 SDK Tools 版本 : 打开 Android SDk Manager, 直接下载最新的 SDK Build Tools 版本;


注意 : Gradle 版本, Gradle 插件版本, SDK Build Tools 版本是相关的, 如果三个版本不兼容, 会出现各种错误, 这里建议都安装最新版本的;




5. 官方依赖库版本



Android 官方依赖库 查询

-- 使用规则 : 编译的 targetVersion 是哪个, 就使用对应版本的依赖库;

-- 依赖库查询 链接 https://developer.android.com/topic/libraries/support-library/features.html;



转载注明出处http://blog.csdn.net/shulianghan/article/details/52097334

2016-08-23 00:08:28 zxccxzzxz 阅读数 4335

以下是我个人遇到过的APP无法安装的一些问题:

  1. 无法安装应用
    • 手机系统版本过低:不符合应用支持的最低版本。(比如应用只支持Android 4.0以上的手机,而手机是Android2.3的)解决方案:换手机;
    • 已存在应用但是再次安装同一个应用导致应用未安装:
      • 下载的应用版本号低于当前已安装的应用版本。解决方案:检查当前已安装应用版本号,下载更新的版本升级;
      • 手机空间不足,本地存储空间不足,导致应用安装解压时出现错误。解决方案:清理手机垃圾,释放更多空间;
      • 没有给予应用安装所需权限。解决方案:设置 — 安全 — 打开安装“未知来源”的应用程序;
    • 手机系统内部还有之前安装包的残留文件,导致再次安装时无法覆盖安装。解决方案:应用完全卸载(设备连接电脑后,在调试模式下通过命令行:adb uninstall <com.xxx.xxx(包名)>来卸载应用)
    • (特殊)手机本机系统错误,导致部分应用安装不上。解决方案:还原出厂设置,有必要时还需要进行双wipe(双清)进行刷机;
    • 安装包解析失败:
      • APK文件损坏;
      • 安装的应用要求最低版本号高于当前手机系统版本;
      • 内存卡格式不对或者已损坏;
  2. 应用无法打开、闪退:
    • 内存占用过高,导致系统强行关闭应用;
    • 应用兼容性问题:
      • 项目中代码引用的类库文件兼容性导致的问题;
      • 应用对32位和64位架构CPU的设备支持不完整(so包支持armabi-v7a);
      • 比如Android Wear/TV(穿戴/电视)的应用就很可能只支持Wear/TV设备,跨平台设备(手机)无法安装。解决方案:买手表换手机。