安卓获取设备及系统信息小结

安卓开发过程中,免不了要获取一些系统信息,大致就是从 Build、PackageInfo、ApplicationInfo、TelephonyManager 四个类中拿。

下面开始介绍四个常用获取设备信息的类:

Build

Build 类可以用来获取Android系统的相关信息。

字段含义示例用法
Build.BRAND产品品牌Meizu通过这个字段可以获取到对用户有意义的手机厂商名称,例如Xiaomi,Meizu,Huawei等。
Build.MANUFACTURER产品制造商Meizu多数品牌会把这个字段的值设置成和Build.BRAND值是一样的(华为这个字段和Build.BRAND有大小写上的差异)。也许Google最初是想把这个字段留给生产手机的代工厂,比如富士康、伟创力之类的,不过显然手机厂商显然都不希望这样使用,把这个字段都填成了自己。
Build.PRODUCT产品型号,产品全称meizu_mx3通过产品型号可以区分不同品牌,也可以区分同一个品牌下不同的产品。
Build.BOARD主板型号meizu_mx3虽然含义上是主板型号,不过有些厂商把这个字段填成了产品型号,或者填一个笼统的型号,显然并不希望被别人获取到这个信息
Build.BOOTLOADERbootloader版本号unknown大多数设备上都获取不到
Build.CPU_ABICPU ABIarmeabi-v7a
Build.CPU_ABI2 CPU第二ABIarmeabi
Build.DEVICE设备型号 mx3
Build.DISPLAY设备的显示信息Flyme OS 4.1.3.5A
Build.FINGERPRINT设备指纹Meizu/meizu_mx3/mx3:4.4.4/
KTU84P/m35x.Flyme_OS_4.1.
3.5.20150111061013:user
/release-keys
Build.HARDWAREmx3
Build.HOSTmz-builder-5
Build.IDKTU84P
Build.MODELM351
Build.RADIOunknown
Build.SERIAL设备序列号351RBJPYUTSO
Build.TAGSrelease-keys
Build.TIME系统build时间
Build.TYPEuser
Build.UNKNOWNunknown
Build.USERflyme
Build.VERSION.CODENAMEREL
Build.VERSION.INCREMENTALm35x.Flyme_OS_4.1.3.5.20150111061013
Build.VERSION.RELEASEAndroid release版本4.4.4
Build.VERSION.SDKAndroid API版本(String类型)19
Build.VERSION.SDK_INTAndroid API版本(int类型)19

TelephonyManager

TelephonyManager 类主要提供了一系列获取手机与通讯相关的状态和信息的get方法,包括手机用户的信息、手机SIM的状态、电信网络的状态等。

TelephonyManager类的对象的获取:

TelephonyManager tm= ( TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

依赖权限:

<!--允许读取电话状态SIM的权限-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!-- 这个权限用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

其他使用方法举例:

public class MainActivity extends Activity {
    private TelephonyManager tm = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);


        TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

        /**
         * 获取当前设备的位置
         */
        tm.getCellLocation().toString();

        /**
         * 获取数据连接状态
         *
         * DATA_CONNECTED 数据连接状态:已连接
         * DATA_CONNECTING 数据连接状态:正在连接
         * DATA_DISCONNECTED 数据连接状态:断开
         * DATA_SUSPENDED 数据连接状态:暂停
         */
        tm.getDataState();

        /**
         * 返回唯一的设备ID
         * 如果是GSM网络,返回IMEI;如果是CDMA网络,返回MEID;如果设备ID是不可用的返回null
         */
        tm.getDeviceId();

        /**
         * 返回设备的软件版本号
         * 例如:GSM手机的IMEI/SV码,如果软件版本是返回null,如果不可用返回null
         */
        tm.getDeviceSoftwareVersion();

        /**
         * 返回手机号码
         * 对于GSM网络来说即MSISDN,如果不可用返回null
         */
        tm.getLine1Number();

        /**
         * 返回当前设备附近设备的信息
         */
        List<NeighboringCellInfo> infos = tm.getNeighboringCellInfo();
        for (NeighboringCellInfo info : infos) {
            //获取邻居小区号
            int cid = info.getCid();
            //获取邻居小区LAC,LAC: 位置区域码。为了确定移动台的位置,每个GSM/PLMN的覆盖区都被划分成许多位置区,LAC则用于标识不同的位置区。
            info.getLac();
            info.getNetworkType();
            info.getPsc();
            //获取邻居小区信号强度
            info.getRssi();
        }

        /**
         * 返回ISO标准的国家码,即国际长途区号
         */
        tm.getNetworkCountryIso();

        /**
         * 返回MCC+MNC代码 (SIM卡运营商国家代码和运营商网络代码)(IMSI)
         */
        tm.getNetworkOperator();

        /**
         * 返回移动网络运营商的名字(SPN)
         */
        tm.getNetworkOperatorName();

        /**
         * 获取网络类型
         *
         * NETWORK_TYPE_CDMA 网络类型为CDMA
         * NETWORK_TYPE_EDGE 网络类型为EDGE
         * NETWORK_TYPE_EVDO_0 网络类型为EVDO0
         * NETWORK_TYPE_EVDO_A 网络类型为EVDOA
         * NETWORK_TYPE_GPRS 网络类型为GPRS
         * NETWORK_TYPE_HSDPA 网络类型为HSDPA
         * NETWORK_TYPE_HSPA 网络类型为HSPA
         * NETWORK_TYPE_HSUPA 网络类型为HSUPA
         * NETWORK_TYPE_UMTS 网络类型为UMTS
         *
         * 在中国,联通的3G为UMTS或HSDPA,移动和联通的2G为GPRS或EGDE,电信的2G为CDMA,电信的3G为EVDO
         */
        tm.getNetworkType();

        /**
         * 返回设备的类型
         *
         * PHONE_TYPE_CDMA 手机制式为CDMA,电信
         * PHONE_TYPE_GSM 手机制式为GSM,移动和联通
         * PHONE_TYPE_NONE 手机制式未知
         */
        tm.getPhoneType();

        /**
         * 返回SIM卡提供商的国家代码
         */
        tm.getSimCountryIso();

        /**
         * 返回MCC+MNC代码 (SIM卡运营商国家代码和运营商网络代码)(IMSI)
         */
        tm.getSimOperator();

        /**
         * 返回服务提供者的名称(SPN)
         */
        tm.getSimOperatorName();

        /**
         * 返回SIM卡的序列号(IMEI),如果是返回null为不可用。
         */
        tm.getSimSerialNumber();

        /**
         * 返回一个常数表示默认的SIM卡的状态。
         *
         * SIM_STATE_ABSENT SIM卡未找到
         * SIM_STATE_NETWORK_LOCKED SIM卡网络被锁定,需要Network PIN解锁
         * SIM_STATE_PIN_REQUIRED SIM卡PIN被锁定,需要User PIN解锁
         * SIM_STATE_PUK_REQUIRED SIM卡PUK被锁定,需要User PUK解锁
         * SIM_STATE_READY SIM卡可用
         * SIM_STATE_UNKNOWN SIM卡未知
         */
        tm.getSimState();

        /**
         * 返回唯一的用户ID,例如,IMSI为GSM手机。
         */
        tm.getSubscriberId();

        /**
         * 获取语音信箱号码关联的字母标识
         */
        tm.getVoiceMailAlphaTag();

        /**
         * 返回语音邮件号码
         */
        tm.getVoiceMailNumber();

        /**
         * 返回手机是否处于漫游状态
         */
        tm.isNetworkRoaming();

        ((TextView) findViewById(R.id.tv_info)).setText(getInfo());
    }

    public String getInfo() {
        String info = "获取设备编号: " + tm.getDeviceId();
        info += "\n获取SIM卡提供商的国家代码: " + tm.getSimCountryIso();
        info += "\n获取SIM卡序列号: " + tm.getSimSerialNumber();
        info += "\n获取网络运营商代号: " + tm.getNetworkOperator();
        info += "\n获取网络运营商名称: " + tm.getNetworkOperatorName();
        info += "\n获取设备当前位置: " + tm.getCellLocation();
        info += "\n获取手机类型: " + tm.getPhoneType();
        info += "\n手机号码: " + tm.getLine1Number();
        info += "\n国际长途区号: " + tm.getNetworkCountryIso();
        info += "\n获取网络类型: " + tm.getNetworkType();
        info += "\n获取数据连接状态: " + tm.getDataState();
        return info;
    }
}

PackageInfo

PackageInfo 用于存储获取到的 Package 的一些信息,这里介绍几个 PackageInfo 中,比较常用的字段:

  • packageName:包名
  • versionCode:版本号
  • versionName:版本名
  • firstInstallTime:首次安装时间
  • lastUpdateTime:最后一次覆盖安装时间

下面是使用代码:

    PackageManager packageManager = getPackageManager();
    PackageInfo packageInfo = null;
        try {
        packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }

    int labelRes = packageInfo.applicationInfo.labelRes;
    String app_name = getResources().getString(labelRes);
    String packageName = packageInfo.packageName;
    int versionCode = packageInfo.versionCode;
    String versionName = packageInfo.versionName;
    long firstInstallTime = packageInfo.firstInstallTime;
    long lastUpdateTime = packageInfo.lastUpdateTime;

ApplicationInfo

ApplicationInfo 用于获取 App 定义在 AndroidManifest.xml 中的一些信息。这些信息是从AndroidManifest.xml 的<application>标签获取的,ApplicationInfo 对象里保存的信息都是<application>标签里的属性值.

这里介绍几个比价常用的:

  • packageName:包名
  • targetSdkVersion:目标 SDK 版本
  • minSdkVersion:最小支持 SDK 版本,有 Api 限制,最低在 Api Level 24 及以上支持
  • sourceDir:App 的 Apk 源文件存放的目录
  • dataDir:data 目录的全路径
  • metaData:Manifest 中定义的 meta 标签数据
  • uid:当前 App 分配的 uid
  • permissions:程序权限数组

下面介绍一些用法:

获取
    try {
        ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName, 0);//全部
		...
    } catch (PackageManager.NameNotFoundException e) {
        return false;
    }
基本信息
//获取应用图标
Drawable drawable = applicationInfo.loadIcon(packageManager);

//获取应用程序的 包名
String appPackageName = applicationInfo.packageName;

//获取应用名
//参数 packageManager  是应用管理者对象 
String appName =applicationInfo.loadLabel(packageManager).toString();

//当我们想在程序debug时打印log,反则不打印log的时候 就需要获取这个debug属性了,可用如下方法获取是否为debug模式
boolean isDebuggable = (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE));
meta-data
<meta-data
	android:name="app_name"
	android:value="弹窗Demo" />

//<application/>标签下metadata获取
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
Bundle metadata = applicationInfo.metaData;//然后通过改bundle获取相应值
metadata.getString("app_name);
获取应用程序对应数据的目录以及占用的空间大小
//获取应用存放数据目录
String dir = applicationInfo.sourceDir;
Log.d("app  ","应用存放数据目录 " +dir);
 
 //获取应用数据大小
ong length = new File(dir).length();

//转换为 M
float size = length*1f/1024/1024;
Log.d("app  ","应用数据大小 " +length+"\t"+size);
判断是否安装在外置储存空间存
//判断是否安装在外存
int flags = applicationInfo.flags;
if((flags&ApplicationInfo.FLAG_EXTERNAL_STORAGE)==ApplicationInfo.FLAG_EXTERNAL_STORAGE){
    Log.d("app  "," 安装在 外置存储空间 ");
}else {
    Log.d("app  "," 安装在 内置存储空间 ");
}
判断应用程序是否是系统应用
//判断是否是系统应用
if((flags&ApplicationInfo.FLAG_SYSTEM)==ApplicationInfo.FLAG_SYSTEM){
    Log.d("app  ","  是系统应用  ");
}else{
    Log.d("app  ","  不是系统应用  ");
}
指定一个Activity来管理数据
/**
  * 从”android:manageSpaceActivity“属性得到
  * 用于指定一个Activity来管理数据,
  * 它最终会出现在设置->应用程序管理中,
  * 默认为按钮为”清除数据”,指定此属性后,该按钮可点击跳转到该Activity, 让用户选择性清除哪些数据。若不设置则为null.
 */
String activityName = applicationInfo.manageSpaceActivityName;
Log.i("applicationInfo", "activityName: " + activityName);
获取应用程序运行的进程
/**
 * 从”android:process“属性得到,注明应用运行的进程名。或不设置则默认为应用包名。
 */
String processName = applicationInfo.processName;
Log.i("applicationInfo", "processName: " + processName);
其他配置信息简述
		// 配置文件中的android:backupAgent属性值,用于备份
        String backupAgentName = applicationInfo.backupAgentName;
        Log.i("applicationInfo", "backupAgentName: " + backupAgentName);
        // 获取继承Application类的对象,维护全局的Application状态
        //但一般都不用继承的方式,可以通过Context.getApplicationContext()方法得到
        String className = applicationInfo.className;
        Log.i("applicationInfo", "className: " + className);

		 /**
         * 可选项,访问当前应用所有组件需要声明的权限,从”android:permission“属性得到。
          */
        String permisson = applicationInfo.permission;
        Log.i("applicationInfo", "permisson: " + permisson);
        // 创建对象时,传入的是GET_SHARED_LIBRARY_FILES该属性才有值
        String[] files = applicationInfo.sharedLibraryFiles;
        Log.i("applicationInfo", "files: " + files);
        // 存放数据的路径  应用数据目录。
        String dataPath = applicationInfo.dataDir;
        Log.i("applicationInfo", "dataPath: " + dataPath);
        // 本地路径  JNI本地库存放路径。
        String nativePath = applicationInfo.nativeLibraryDir;
        Log.i("applicationInfo", "nativePath:" + nativePath);
        // 公共资源路径
        String punlicSourcePath = applicationInfo.publicSourceDir;
        Log.i("applicationInfo", "punlicSourcePath: " + punlicSourcePath);
        // 资源路径  应用APK的全路径
        String sourcePath = applicationInfo.sourceDir;
        Log.i("applicationInfo", "sourcePath: " + sourcePath);

        /**
         * 当前应用所有Activity的默认task密切性。
         * 可以参考ActivityInfo的taskAffinity,从”android:taskAffinity“属性得到。
         * 具体taskAffinity是怎么影响到Activity在task的启动, 后面会在Activity启动模式中细讲
         */
        String taskAffinity = applicationInfo.taskAffinity;
        Log.i("applicationInfo", "taskAffinity: " + taskAffinity);
        // 如果是false,代表application里的所有组件都禁用
        boolean enable = applicationInfo.enabled;
        Log.i("applicationInfo", "enable: " + enable);
        // 表述资源文件的标识
        int descriRes = applicationInfo.descriptionRes;
        Log.i("applicationInfo", "descriRes: " + descriRes);
        int flag = applicationInfo.flags;
        Log.i("applicationInfo", "flag: " + flag);
        // 指定smallest screen width的值,超过这个值,就要开启屏幕兼容
        int compatibleWidth = applicationInfo.compatibleWidthLimitDp;//android:compatibleWidthLimitDp属性
        Log.i("applicationInfo", "compatibleWidth: " + compatibleWidth);
        // 同上,只是这时候用户无法禁止屏幕兼容模式,说明是强制启动屏幕兼容
        int largestWidth = applicationInfo.largestWidthLimitDp;//android:largestWidthLimitDp属性
        Log.i("applicationInfo", "largestWidth: " + largestWidth);
        // 所需屏幕空间的最短尺寸,
        int samllestWidth = applicationInfo.requiresSmallestWidthDp;//android:requiresSmallestWidthDp属性
        Log.i("applicationInfo", "samllestWidth: " + samllestWidth);
        // 应用所需的最小sdk版本
        int sdkVersion = applicationInfo.targetSdkVersion;
        Log.i("applicationInfo", "sdkVersion: " + sdkVersion);
        int theme = applicationInfo.theme;
        Log.i("applicationInfo", "theme: " + theme);//android:theme=
        int uid = applicationInfo.uid;
        Log.i("applicationInfo", "uid: " + uid);
        // 配置文件中的uiOptions属性的值
        int uiOptions = applicationInfo.uiOptions;
        Log.i("applicationInfo", "uiOptions: " + uiOptions);

工具类

尴尬了,之前直接复制别人的工具类,发现写的乱七八糟,自己用的时候老脸都没了,下面自己写了一遍,用的 kotlin,下面看代码:

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.os.Build
import android.telephony.TelephonyManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

/**
 * 获取手机详细信息
 * 详细说明可以看我博客:https://blog.csdn.net/lfq88/article/details/118088991
 */
@Suppress("unused")
object DeviceInfoModel {

    /**
     * 获取机型
     *
     * @return xxx
     */
    val phoneModel: String
        get() {
            val brand = Build.BRAND //手机品牌
            val model = Build.MODEL //手机型号
            return "${brand}_${model}"
        }

    /**
     * 获取操作系统
     *
     * @return xxx
     */
    val oS: String
        get() = "Android" + Build.VERSION.RELEASE

    /**
     * 获取手机分辨率
     *
     * @param context context
     * @return 手机分辨率
     */
    fun getResolution(context: Context): String {
        val screenWidth = context.resources.displayMetrics.widthPixels
        val screenHeight = context.resources.displayMetrics.heightPixels
        return "$screenWidth*$screenHeight"
    }

    /**
     * 获取 MEID
     *
     * @param context context
     * @return 唯一设备号
     */
    @SuppressLint("MissingPermission", "HardwareIds")
    fun getMEID(context: Context): String {
        if (!checkReadPhoneStatePermission(context)) {
            return ""
        }
        val meid: String
        val mTelephonyMgr = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        //Android版本大于o-26-优化后的获取
        meid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mTelephonyMgr.meid
        } else {
            mTelephonyMgr.deviceId
        }
        return meid
    }

    /**
     * 获取唯一设备号
     *
     * @param context context
     * @return 唯一设备号
     */
    @SuppressLint("MissingPermission")
    fun getIMEI(context: Context, index: Int): String {
        if (!checkReadPhoneStatePermission(context)) {
            return ""
        }
        var imei = ""
        val manager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

        //Android版本大于o-26-优化后的获取
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            imei = manager.getImei(index)
        } else {
            //通过反射获取
            try {
                val method = manager.javaClass.getMethod("getDeviceIdGemini", Int::class.javaPrimitiveType)
                imei = method.invoke(manager, index) as String
            } catch (e: Exception) {
                try {
                    val method = manager.javaClass.getMethod("getDeviceId", Int::class.javaPrimitiveType)
                    imei = method.invoke(manager, index) as String
                } catch (e1: Exception) {
                    e1.printStackTrace()
                }
            }
        }
        return imei
    }

    //获取卡1的IMEI
    fun getIMEI(context: Context): String {
        return getIMEI(context, 0)
    }

    //获取卡2的IMEI
    fun getIMEI2(context: Context): String {
        return getIMEI(context, 1)
    }

    //检查是否有获取手机信息权限
    private fun checkReadPhoneStatePermission(context: Context): Boolean {
        try {
            if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
                != PackageManager.PERMISSION_GRANTED
            ) {
                ActivityCompat.requestPermissions(
                    (context as Activity), arrayOf(Manifest.permission.READ_PHONE_STATE),
                    10
                )
                return false
            }
        } catch (e: IllegalArgumentException) {
            return false
        }
        return true
    }

    /**
     * 获取运营商(不推荐)
     *
     * @param context xxx
     * @return xxx
     */
    fun getNetOperator(context: Context): String {
        val manager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        return when(manager.simOperator) {
            "46000","46002","46007"->"中国移动"
            "46001","46006","46009"->"中国电信"
            "46003","46005","46011"->"中国联通"
            else -> "未知"
        }
    }

    /**
     * 获取联网方式
     */
    @SuppressLint("MissingPermission")
    fun getNetMode(context: Context): String {
        var strNetworkType = "未知"
        val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

        val networkInfo = manager.activeNetworkInfo//此处需要权限
        if (networkInfo != null && networkInfo.isConnected) {
            val netMode = networkInfo.type

            //wifi
            if (netMode == ConnectivityManager.TYPE_WIFI) {
                strNetworkType = "WIFI"
            } else if (netMode == ConnectivityManager.TYPE_MOBILE) {
                val networkType = networkInfo.subtype
                strNetworkType = when (networkType) {
                    TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_IDEN -> "2G"
                    TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyManager.NETWORK_TYPE_HSPAP -> "3G"
                    TelephonyManager.NETWORK_TYPE_LTE -> "4G"
                    else -> {
                        val _strSubTypeName = networkInfo.subtypeName
                        if (_strSubTypeName.equals("TD-SCDMA",ignoreCase = true)|| _strSubTypeName.equals("WCDMA", ignoreCase = true)|| _strSubTypeName.equals("CDMA2000", ignoreCase = true)) {
                            "3G"
                        } else {
                            _strSubTypeName
                        }
                    }
                }
            }
        }
        return strNetworkType
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值