Android 获取手机名称

1. 需求

在这里插入图片描述
获取框中的手机名称,注意这里与其他文章不一样的地方,这个手机名称可以修改,并且会作用于蓝牙以及热点等功能。

2. 问题分析

首先查阅了网上关于获取手机名称或者设备名称的解决方案,一般包括两种:

2.1 Build.MODEL

显然这个名称与目标完全不符,自行尝试

2.2 BluetoothAdapter.getName()

这个是一个解决方法,但是当关闭蓝牙后再修改手机名称的话,通过这个方式获取的是旧名称,修改后的名称获取不到

也就是说,网上给出的解决方法已经到了尽头,需要自己找个解决方案,那么我的分析思路:

  1. 先查看Build.MODEL源码,发现最后是通过SystemProperties.get(property, UNKNOWN)得到属性,传入的值是属性对应的键,比如MODEL对应ro.product.model,那么手机名称是否也是类似的键值属性呢;
  2. 搜索ro.product.model和SystemProperties相关的内容,我了解了它确实是可以获取系统属性的,我感觉手机名称也属于系统属性,因此继续搜索下去;
  3. 后来查到了通过命令adb shell getprop > prop.txt可以导出系统属性,那么我来看看结果是什么,果然,这个文件中包括了“小米手机”这个名称,然后修改名称再看一次,发现确实是对应的,那么我们就获得了key:persist.sys.device_name,同时找到ro.product.model对应的值,这样就确定可以通过SystemProperties得到结果;
  4. 又因为SystemProperties不能直接使用,那么寻找其他办法,显然可以通过反射使用get方法,那么就尝试一下,当然还有另一个方式就是通过代码执行cmdgetprop,这里就仅用反射吧。
[persist.sys.dalvik.vm.lib.2]: [libart.so]
[persist.sys.datastall.detect]: [0]
[persist.sys.device_name]: [小米手机]
[persist.sys.enable_inputopts]: [true]
[persist.sys.enable_ioprefetch]: [false]

3. 代码

通过反射将key传入,得到deviceName,最终任务完成,搞定

String deviceName = "";
try{
    Class<?> cls = Class.forName("android.os.SystemProperties");
    Object object = (Object) cls.newInstance();
    Method getName = cls.getDeclaredMethod("get", String.class);
    deviceName = (String) getName.invoke(object, "persist.sys.device_name");
} catch (Exception e){
    e.printStackTrace();
}

4. 测试

MIUI可以,其他系统GG,其他系统类似华为、三星都失败了,从prop.txt文件来看,并没有将谁被名称存在系统配置文件中。那么问题来了,这个属性去哪了?

5. 再分析

如果从目标往前走已经是死路了,那么不妨从前往后走,我们从设置手机名称这个地方寻找它调用了什么方法,说不定就能发现一些东西。

显然,Android开源的优势体现出来,在查询了Google关于Android的源码后我发现,在关于手机这个界面,保存和获取手机名称都是在一个类叫做DeviceManager中实现的,具体相关的两部分代码为

package com.android.tv.settings.name;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.provider.Settings;
public class DeviceManager {
    /**
     * Retrieves the name from Settings.Global.DEVICE_NAME
     *
     * @param context A context that can access Settings.Global
     * @return The device name.
     */
    public static String getDeviceName(Context context) {
        return Settings.Global.getString(context.getContentResolver(), Settings.Global.DEVICE_NAME);
    }
    /**
     * Sets the system device name.
     *
     * For now it will explicitly call the different discoverable services that haven't been ported
     * to use the Settings.Global.DEVICE_NAME entry.
     *
     * @param context A context that can access Settings.Global
     * @param name The new device name.
     */
    public static void setDeviceName(Context context, String name) {
        Settings.Global.putString(context.getContentResolver(), Settings.Global.DEVICE_NAME, name);
        BluetoothAdapter.getDefaultAdapter().setName(name);
    }
}

由上面的代码可知,原生Android在保存设备名称时会同时保存蓝牙的名称,而获取名称时是从Settings.Global中获取的,因此如果我们要在代码里得到设备名称,理论上应该也可以通过Settings.Global得到。

但是,根据我的测试,小米/三星/华为这三家都将Settings.Global设置为一个定值,也就是说,他们修改了这里的存储逻辑,在不知道系统源码的情况下我们应该是拿不到设别名称,除非通过蓝牙得到(但是蓝牙获取有Bug),而小米是个例外,他存储设备名称的位置被我碰巧找到了,所以这个需求还是没办法完美的实现,主要是各个Android厂商背锅。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值