Android 获取手机运营商、有无sim卡

名词解释

MCC

Mobile Country Code:移动国家代码,由3位数字组成,唯一地识别移动用户所属的国家。MCC由国际电联(ITU)统一分配和管理,一旦分配就不可更改。所以一个MCC只能对应一个国家,但是一个国家可以被分配多个MCC。比如美国的MCC有310,311和316。中国的 MCC只有460。

MNC

Mobile Network Code:移动网络代码,共2位,中国移动TD系统使用00,中国联通GSM系统使用01,中国移动GSM系统使用02,中国电信CDMA系统使用03。它与MCC合起来唯一标识一个移动网络提供者,比如中国移动46002。

Tips:MCC+MNC就可以唯一确定一个移动网络运营商。比如中国移动为46000。

IMSI

International mobile subscriber identity:国际移动用户识别码。 国际上为唯一识别一个移动用户所分配的号码,存于SIM卡中。IMSI共有15位,其结构如下:MCC+MNC+MSIN (MNC+MSIN=NMSI),一个典型的IMSI号码为460030912121001。所以MCC和MNC可以通过截取IMSI的前3位和次2次来获取。

延伸

从技术上讲,IMSI可以彻底解决国际漫游问题。但是由于北美目前仍有大量的AMPS系统使用MIN号码,且北美的MDN和MIN采用相同的编号,系统已经无法更改,所以目前国际漫游暂时还是以MIN为主。其中以O和1打头的MIN资源称为IRM(International Roaming MIN),由IFAST (International Forum on ANSI-41 Standards Technology)统一管理。目前联通申请的IRM资源以09打头。可以看出,随着用户的增长,用于国际漫游的MIN资源将很快耗尽,全球统一采用IMSI标识用户势在必行。

IMEI

IMEI(International Mobile Equipment Identity)是国际移动设备识别码,是由15位数字组成的"电子串号",它与每台移动电话机一一对应,而且该码是全世界唯一的,存于设备中。每一只移动电话机在组装完成后都将被赋予一个全球唯一的一组号码,这个号码从生产到交付使用都将被制造生产的厂商所记录。从这个定义上看,无论是单卡手机还是双卡手机,都应该只有一个IMEI号,但是移动设备开发规范里面明确定义,IMEI和IMSI存在一一对应的关系,所以双卡手机会有两个IMEI号。一个IMEI对应两个IMSI (SIM卡)的情况是规范里没有定义的,所以两个IMEI相对安全一些。如果两个IMSI(SIM卡)对应同一个IMEI,相当于有一个是不合法的。有些地方,比如印度什么的,检查IMEI号,两个卡用同一个IMEI号就会出现问题。所以支持双卡的手机有两个IMEI号。

获取手机运营商

有了上述知识,再查询三大运营商的MNC(https://baike.baidu.com/item/MNC/55596?fr=aladdin),就可以得到以下实现方法,需要说明的是,双卡手机由于拨号和上网可以分别设置为不同的sim卡,所以根据业务需求就有了 `获取设备拨号运营商` 以及 `获取设备蜂窝网络运营商` 两种方法,其实主要差别只在:

 

// 用于判断拨号运营商
TelephonyManager.getNetworkOperator();
//  用于判断蜂窝网络运营商
TelephonyManager.getSimOperator();

 

	/**
	 * 获取设备拨号运营商
	 *
	 * @return ["中国电信CTCC":3]["中国联通CUCC:2]["中国移动CMCC":1]["other":0]["无sim卡":-1]
	 */
	public static int getSubscriptionOperatorType() {
		int opeType = -1;
		// No sim
		if (!hasSim()) {
			return opeType;
		}

		TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
		String operator = tm.getNetworkOperator();
		// 中国联通
		if ("46001".equals(operator) || "46006".equals(operator) || "46009".equals(operator)) {
			opeType = 2;
			// 中国移动
		} else if ("46000".equals(operator) || "46002".equals(operator) || "46004".equals(operator) || "46007".equals(operator)) {
			opeType = 1;
			// 中国电信
		} else if ("46003".equals(operator) || "46005".equals(operator) || "46011".equals(operator)) {
			opeType = 3;
		} else {
			opeType = 0;
		}
		return opeType;
	}

	/**
	 * 获取设备蜂窝网络运营商
	 *
	 * @return ["中国电信CTCC":3]["中国联通CUCC:2]["中国移动CMCC":1]["other":0]["无sim卡":-1]["数据流量未打开":-2]
	 */
	public static int getCellularOperatorType() {
		int opeType = -1;
		// No sim
		if (!hasSim()) {
			return opeType;
		}
		// Mobile data disabled
		if (!isMobileDataEnabled(MobSDK.getContext())) {
			opeType = -2;
			return opeType;
		}
		// Check cellular operator
		TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
		String operator = tm.getSimOperator();
		// 中国联通
		if ("46001".equals(operator) || "46006".equals(operator) || "46009".equals(operator)) {
			opeType = 2;
			// 中国移动
		} else if ("46000".equals(operator) || "46002".equals(operator) || "46004".equals(operator) || "46007".equals(operator)) {
			opeType = 1;
			// 中国电信
		} else if ("46003".equals(operator) || "46005".equals(operator) || "46011".equals(operator)) {
			opeType = 3;
		} else {
			opeType = 0;
		}
		return opeType;
	}

	/**
	 * 判断数据流量开关是否打开
	 *
	 * @param context
	 * @return
	 */
	public static boolean isMobileDataEnabled(Context context) {
		try {
			Method method = ConnectivityManager.class.getDeclaredMethod("getMobileDataEnabled");
			method.setAccessible(true);
        	ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        	return (Boolean) method.invoke(connectivityManager);
    	} catch (Throwable t) {
			Log.d("isMobileDataEnabled", "Check mobile data encountered exception");
			return false;
		}
	}

/**
 * 检查手机是否有sim卡
 */
private boolean hasSim(Context context) {
	TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
	String operator = tm.getSimOperator();
	if (TextUtils.isEmpty(operator)) {
		return false;
	}
	return true;
}

上述代码中没有中国铁通,需要的人可以自己加上去(中国铁通:46020)。另外,需要的权限检查也可以根据需要添加,需以下权限:

android.permission.READ_PHONE_STATE

Android Q适配

Android Q对设备不可重置的标识符做了安全性限制,无法再通过 `TelephonyManager.getSimSerialNumber()` 方法获得sim卡序列号,为了适配Q,可以改用以下方法判断是否有sim卡:

	/**
	 * 判断是否有Sim卡
	 *
	 * @return
	 */
	public static boolean hasSim() {
		TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
		if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
			return true;
		} else {
			return false;
		}
	}

 

 

你可能感兴趣的:(Android)