安卓开发过程中,免不了要获取一些系统信息,大致就是从 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.BOOTLOADER | bootloader版本号 | unknown | 大多数设备上都获取不到 |
Build.CPU_ABI | CPU ABI | armeabi-v7a | |
Build.CPU_ABI2 CPU | 第二ABI | armeabi | |
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.HARDWARE | mx3 | ||
Build.HOST | mz-builder-5 | ||
Build.ID | KTU84P | ||
Build.MODEL | M351 | ||
Build.RADIO | unknown | ||
Build.SERIAL | 设备序列号 | 351RBJPYUTSO | |
Build.TAGS | release-keys | ||
Build.TIME | 系统build时间 | ||
Build.TYPE | user | ||
Build.UNKNOWN | unknown | ||
Build.USER | flyme | ||
Build.VERSION.CODENAME | REL | ||
Build.VERSION.INCREMENTAL | m35x.Flyme_OS_4.1.3.5.20150111061013 | ||
Build.VERSION.RELEASE | Android release版本 | 4.4.4 | |
Build.VERSION.SDK | Android API版本(String类型) | 19 | |
Build.VERSION.SDK_INT | Android 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
}
}