Android 8、Android 9获取手机序列号的兼容写法

随着Android 版本的更新,获取手机序列号的方式也有所不同。最近咋工作中看到了,查阅资料在这里总结下目前。

一、获取序列号


public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int CODE_READ_PHONE_STATE = 0x11;
    private String serialNumber = "UNKNOWN";

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


    @RequiresApi(api = Build.VERSION_CODES.O)
    public void checkPermission() {
        if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, CODE_READ_PHONE_STATE);
        } else {
            serialNumber = Build.getSerial();
        }
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    @SuppressLint("MissingPermission")
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == CODE_READ_PHONE_STATE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            serialNumber = Build.getSerial();
        } else {
            Log.i(TAG, "you deny the permission:READ_PHONE_STATE");
        }
    }

    @SuppressLint("HardwareIds")
    public String getSerialNumber() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {// android Q(安卓10)
             // TODO use yourself style
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { // android O_MR1(安卓8.1)、android P(安卓 9)
            checkPermission();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){// android O(安卓 8.0)
            this.serialNumber = Build.SERIAL;
        }else {//below android 8.0
            try {
             // 方式1:执行adb 命令获得
                Runtime runtime = Runtime.getRuntime();
                Process process = null;
                process = runtime.exec("getprop ro.serialno");
                InputStream is = process.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                this.serialNumber = br.readLine();
                // 方式2:反射获得(不推荐使用)
//                Class c = Class.forName("android.os.SystemProperties");
//                Method get = c.getMethod("get", String.class);
//                serialNumber = (String) get.invoke(c, "ro.serialno");
//                Log.i(TAG, "  sdk version low android O ,reflect get" + serialNumber);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return serialNumber;
    }
}

二、测试过程及其结论

1、有关Build.SERIAL字段获取方式

测试结论:
1、安卓8.0及8.0以下可以获得结果。
2、安卓8.1及其以上返回UNKNOWN
文档说明:如下图。
3、8.0时废弃啦,8.0及其以上版本建议使用getSerial()方法代替。

Android 8、Android 9获取手机序列号的兼容写法_第1张图片
个人结论

8.0还可以用这个方式获取,因为getSerial()方式需要“read phone state” 权限,而读取手机权限时总要去让用户决定,相对来说有点限制。

2、有关Build.getSerial()获取方式

(1)测试结论

1、安卓10(api 29)手机上直接崩溃(api28以上)
2、安卓8.0(api 26)、安卓9(api 28)上可以获得,需要“read phone state” 权限,否则崩溃
小结论:Build.getSerial()是安卓8.0-9.0上Build.SERIAL废弃后的替代方案。

(2)Build.getSerial()的官方api参考

1、Requires Permission: READ_PRIVILEGED_PHONE_STATE

2、If the calling app's target SDK is API level 28 or lower and the app has the
     READ_PHONE_STATE permission then {@link Build#UNKNOWN} is returned.
3、If the calling app's target SDK is API level 28 or lower and the app does not have
     the READ_PHONE_STATE permission, or if the calling app is targeting API level 29 or
     higher, then a SecurityException is thrown

1、需要READ_PRIVILEGED_PHONE_STATE(READ_PHONE_STATE也行)
2、如果调用应用程序的目标SDK是API级别28或更低,并且应用程序具有READ_PHONE_STATE权限,那么返回#UNKNOWN
3、如果调用应用程序的目标SDK是API级别28或更低,且应用程序没有READ_PHONE_STATE权限,或者如果调用应用程序的目标API级别29或更高,则抛出SecurityException。
ps:总感觉官方这段注释写的有点怪怪的(参考上述个人测试结论)

3、有关8.0以下获取方式

(1)Build.SERIAL获取

这种获取方式支持到8.0及其以下,但会8.0以下网上文章好多都使用反射获得,这里大家合理选择吧!!!

(2)adb 命令或者反射获取测试

1、二者在8.0(>=8.0)版本上获取值为空,8.0以下可以获得
2、不建议使用反射方式获取。(如下图)

在这里插入图片描述

4、有关10.0及其更高版本的替代方案

这里建议自己实现:
实现参考如下:
1、官方建议
2、前人实践

The end

给出了自己总结的一种方案,,,,,溜溜球。

你可能感兴趣的:(android)