关于android读取ICCID、IMSI和IMEI

本文详细解析了Android系统中获取手机标识符如IMEI、IMSI等的方法,并澄清了常见误解,例如如何正确获取SIM卡序列号(ICCID)而不是误认为是IMEI。

原文地址: http://blog.sina.com.cn/s/blog_560e7f660101gzw1.html


2010年原创于http://labs.chinamobile.com/mblog/427_62947,竟然有人原封不动的写在自己的sina博客里。
我们说一下大家在做android客户端软件存在的一个问题,msisdn一般很难拿到没法直接标识用户,只能采取注册用户的方法,如果你是互联网服务已有的用户可以直接登录,如果不是的话用户一看到注册是否就会跑掉大半。
这里会引出下一个问题,就是那ICCID、MSISDN、ISMI到底从哪来是最准确的呢?实际上android也是通过读取卡片相关数据获取的,因此卡内存储的数据是最准确的,那么问题来了是否我们的应用可以自己读取卡内相关文件获取这些数据呢?这个要在开一个专题聊了,敬请期待。
msisdn目前的方法是通过客户端给自己的后台发一个短信,由运营商的网络将此短信附加上MSISDN,我们也就有了用户的标识。
再来看看http://developer.android.com/reference/android/telephony/TelephonyManager.html说明的是否和我当初的写法一致:
getSubscriberId()
Returns the unique subscriber ID, for example, the IMSI for a GSM phone.


getSimSerialNumber()
Returns the serial number of the SIM, if applicable.


getLine1Number()
Returns the phone number string for line 1, for example, the MSISDN for a GSM phone.
getDeviceId()
Returns the unique device ID, for example, the IMEI for GSM and the MEID or ESN for CDMA phones.
1.从一个错误代码引出我们的讨论:
android公开的API提供了访问方法,大家都知道使用TelephonyManager提供的方法,但是有些理解有误,如下国内一个比较大的andorid论坛提供的例子,就出现了错误:
帖子如下http://www.eoeandroid.com/thread-14027-1-3.html,其中实现代码没有注释,只能按照变量定义判断:
        TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
        String deviceid = tm.getDeviceId();
        String tel = tm.getLine1Number();     //取出用户手机号码?
        String imei =tm.getSimSerialNumber();  //取出IMEI?
        String imsi =tm.getSubscriberId();     //取出IMSI?


那么上述出现错误了:String imei =tm.getSimSerialNumber();  //取出IMEI
IMEI是手机的序列号,怎么会通过getSimSerialNumber()方法获得,那么查一下andorid源码可以看出:
http://www.netmite.com/android/mydroid/frameworks/base/telephony/java/android/telephony/TelephonyManager.java
从注释里明显看出来这个函数是取SIM卡序列号的,也就是ICCID的,他用错了。


public String getSimSerialNumber() {
try {
return getSubscriberInfo().getSimSerialNumber();
} catch (RemoteException ex) {
}
return null;
}
2.相关几个定义、说明:
我们说到的和手机、卡相关的号码数据包括IMSI,MSISDN,ICCID,IMEI
IMSI:international mobiles subscriber identity国际移动用户号码标识,
这个一般大家是不知道,GSM必须写在卡内相关文件中;
MSISDN:mobile subscriber ISDN用户号码,这个是我们说的139,136那个号码;
ICCID:ICC identity集成电路卡标识,这个是唯一标识一张卡片物理号码的;
IMEI:international mobile Equipment identity手机唯一标识码;
3.那好我们看看andorid实现TelephonyManager.java的源码:
getDeviceId()取IMEI号没有争议了。


    public String getDeviceId() {
        try {
            return getSubscriberInfo().getDeviceId();
        } catch (RemoteException ex) {
        }
        return null;
    }
getLine1Number()取MSISDN,这个需要说明两点,1为什么这个函数叫getLine1Number(),因为andorid实现的时候应该分为GSM和CDMA的,GSM手机使用这个函数,CDMA应该还会由其它实现的。
2取MSISDN具体的方法就会导致最后能否取到了,函数中调用了getSubscriberInfo().getLine1Number()去实现,我们下面找找看。


    public String getLine1Number() {
        try {
            return getSubscriberInfo().getLine1Number();
        } catch (RemoteException ex) {
        }
        return null;
    }
找到了private IPhoneSubInfo getSubscriberInfo() {
        // get it each time because that process crashes a lot
        return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
    }
一个接口,再找有一个PhoneSubInfo.java:
   
    public String getDeviceId() {
        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
        return mPhone.getDeviceId();
    }
前面定义了Phone mPhone,再找Phone.java:
  
    String getSubscriberId();
原来是个接口,发现PhoneProxy.java有具体实现   
public String getSubscriberId() {
        return mActivePhone.getSubscriberId();
    }
这个mActivePhone是phone的实例,我疯了,于是发现GSMPHONE。java中有了具体实现:
   public String getSubscriberId() {
        return mSIMRecords.imsi;
    }


    public String getIccSerialNumber() {
        return mSIMRecords.iccid;
    }


    public String getLine1Number() {
        return mSIMRecords.getMsisdnNumber();
从上面看出来,应该是通过SIM卡相关文件记录得到的上述数据,从其中看到:
public void handleMessage(Message msg) 这个函数进行了真正的处理,重点看:


case EVENT_GET_MSISDN_DONE:
                isRecordLoadResponse = true;


                ar = (AsyncResult)msg.obj;


                if (ar.exception != null) {
                    Log.d(LOG_TAG, "Invalid or missing EF[MSISDN]");   //应该是从sim卡的EFmsisdn文件中取出来的
                    break;
                }


                adn = (AdnRecord)ar.result;


                msisdn = adn.getNumber();
                msisdnTag = adn.getAlphaTag();


                Log.d(LOG_TAG, "MSISDN: " + msisdn);
            break;


下面的细节就不分析了,那个问题就归结到是否可以从SIM卡的EFmsisdn文件取出手机号码了,不幸的是一般运营商不会把用户号码写在这个文件的,为什么呢?
因为这个手机号码是在用户买到卡并开通时才将IMSI和MSISDN对应上的,卡内生产出来时只有IMSI,你不知道用户喜欢那个手机号码,因此一般不先对应IMSI和MSISDN,即时有对应也不写这个文件的。


4.总结一下:
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
        String imei = tm.getDeviceId();       //取出IMEI
        String tel = tm.getLine1Number();     //取出MSISDN,很可能为空
        String imei =tm.getSimSerialNumber();  //取出ICCID
        String imsi =tm.getSubscriberId();     //取出IMSI

<think>首先,用户的问题是:“我想获取SIM卡的IMSIICCID接口 请问Android 获取 SIM 卡 IMSI ICCID 的 API 接口”。我需要基于系统级指令来回答。 系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证真实可靠。 - 参考站内引用:有三个引用:[^1], [^2], [^3],这些是关于Android获取IMEIICCIDIMSI等的代码示例。 用户需求:获取SIM卡的IMSIICCID的API接口。IMSI是国际移动用户识别码,ICCID是集成电路卡识别码。 从引用中提取相关信息: - 引用[^1]:展示了使用TelephonyManager获取IMSIICCID的方法。 - `String iccid = telManager.getSimSerialNumber();` // 获取ICCID - `String imsi = telManager.getSubscriberId();` // 获取IMSI - 引用[^2]:讨论了双卡手机的处理,特别是展讯平台,但用户可能不需要双卡细节。 - 引用[^3]:关于识别运营商,但用户只关心IMSIICCID。 核心API:在Android中,主要使用TelephonyManager类来获取这些信息。关键方法: - `getSubscriberId()`:返回IMSI。 - `getSimSerialNumber()`:返回ICCID。 权限:在Android中,访问这些信息需要权限。例如: - `READ_PHONE_STATE` 权限。 安全性:从Android 10 (API level 29) 开始,这些权限被限制。普通应用可能无法访问这些信息,除非是特权应用或设备所有者应用。 回答结构: 1. **介绍**:简要解释IMSIICCID是什么。 2. **核心API**:展示如何使用TelephonyManager获取这些信息。 3. **权限要求**:说明所需的权限。 4. **注意事项**:讨论Android版本兼容性限制。 5. **代码示例**:提供简单的Java或Kotlin代码示例。 6. **相关问题**:生成相关问题。 确保使用中文回答。 生成相关问题:基于主题,生成2-3个相关问题。 添加引用:在相关段落末尾添加[^1], [^2], [^3]作为引用标识。引用来自提供的站内引用。 现在,构建回答: - 开头:直接回答问题。 - 步骤: - 步骤1:获取TelephonyManager实例。 - 步骤2:调用方法获取IMSIICCID。 - 步骤3:处理权限兼容性。 - 代码示例:提供简单代码。 - 结尾:相关问题。 引用应用: - 当提到获取IMSIICCID时,引用[^1],因为它有直接代码。 - 如果需要双卡处理,引用[^2]。 - 运营商识别引用[^3]。 用户没有指定双卡,所以专注于单卡场景。 最终回答结构: 1. 介绍IMSIICCID。 2. API解释。 3. 权限说明。 4. 代码示例。 5. 注意事项。 6. 相关问题。</think>### Android 获取 SIM 卡 IMSI ICCID 的 API 接口 在 Android 开发中,获取 SIM 卡的 IMSI(国际移动用户识别码) ICCID(集成电路卡识别码)主要通过 `TelephonyManager` 类实现。IMSI 用于识别用户所属运营商,而 ICCID 是 SIM 卡本身的唯一序列。以下我将逐步解释核心 API、权限要求实现方法,确保回答真实可靠(基于 Android 官方文档常见实践)。 #### 1. **核心 API 接口** - **`TelephonyManager` 类**:这是 Android 系统提供的核心服务类,用于访问 SIM 卡信息。 - **获取 IMSI**:使用 `getSubscriberId()` 方法。该方法返回 SIM 卡的 IMSI 字符串。 - **获取 ICCID**:使用 `getSimSerialNumber()` 方法。该方法返回 SIM 卡的 ICCID 字符串。 - 这些方法在 `android.telephony.TelephonyManager` 类中定义,适用于大多数 Android 设备[^1]。 #### 2. **权限要求** - 在 Android 中,访问 IMSI ICCID 需要声明 `READ_PHONE_STATE` 权限。此权限必须在 `AndroidManifest.xml` 文件中添加: ```xml <uses-permission android:name="android.permission.READ_PHONE_STATE" /> ``` - **运行时权限**:从 Android 6.0(API level 23)开始,还需在代码中动态请求该权限: - 使用 `ActivityCompat.requestPermissions()` 或类似方法处理权限请求。 - 未处理权限可能导致安全异常(如 `SecurityException`)。 #### 3. **代码实现示例** 以下是一个简单的 Java 代码示例,展示如何获取 IMSI ICCID: ```java import android.content.Context; import android.telephony.TelephonyManager; import androidx.core.app.ActivityCompat; // 用于权限处理 public class SimCardUtils { public static void getSimInfo(Context context) { // 获取 TelephonyManager 实例 TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); // 检查权限(简化示例,实际需动态请求) if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { // 获取 IMSI String imsi = telManager.getSubscriberId(); // 返回 IMSI 字符串 // 获取 ICCID String iccid = telManager.getSimSerialNumber(); // 返回 ICCID 字符串 // 输出结果(实际应用中可处理或存储) Log.d("SimInfo", "IMSI: " + imsi + ", ICCID: " + iccid); } else { // 处理权限未授予的情况 Log.e("SimInfo", "READ_PHONE_STATE permission not granted"); } } } ``` - **说明**: - `getSubscriberId()` `getSimSerialNumber()` 是同步方法,调用时需确保在主线程或异步任务中执行。 - 如果 SIM 卡未插入或设备不支持,这些方法可能返回 `null`[^1]。 - 对于双卡设备,需使用 `TelephonyManager` 的扩展方法(如 `createForSubscriptionId(int subId)`),但单卡场景下上述代码通用[^2]。 #### 4. **注意事项** - **Android 版本限制**: - 在 Android 10(API level 29)及更高版本,普通应用无法访问 IMSI ICCID 等敏感信息,除非应用是设备所有者或特权应用(如系统应用)。这是出于隐私保护考虑。 - 建议检查设备 API level:`Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q`。 - **返回值处理**: - IMSI 格式通常为 15 位数字(如 `310150123456789`),ICCID 为 19-20 位数字。 - 可结合运营商识别逻辑(如解析 MCC/MNC),但用户问题聚焦于 API 接口,此处不展开[^3]。 - **安全性警告**: - IMSI ICCID 是敏感信息,存储或传输时需加密。 - 避免在非必要场景使用,以防违反 Google Play 政策。 #### 5. **相关问题** 基于您的查询,以下是几个扩展问题: 1. 如何在 Android 双卡设备中分别获取两张 SIM 卡的 IMSI ICCID? 2. Android 10 及以上版本如何替代 IMSI/ICCID 获取方法以满足隐私政策? 3. 如何通过 IMSI 识别 SIM 卡所属运营商(如中国移动、中国联通)? 如果您需要双卡处理、权限请求完整代码或运营商识别逻辑,我可以进一步详细解答。 [^1]: 引用[1]:获取手机IMEI/ICCID/IMSI。TelephonyManager telManager = (TelephonyManager) this .getSystemService(Context.TELEPHONY_SERVICE); String imsi =telManager.getSubscriberId(); //取出IMSI:国际移动用户识别码(就是识别你是哪个运营商的SIM卡) String iccid =telManager.getSimSerialNumber(); //取出ICCID:集成电路卡识别码(固化在手机SIM卡中,就是SIM卡的序列)很容易伪造哦。 [^2]: 引用[2]:关于android各种双卡手机获取imeiimsi的处置(mtk,展讯,高通等)。 下面是展讯平台的(貌似市面上手机不多啊): private static void initSpreadDoubleSim() { try { Class<?> c = Class .forName("com.android.internal.telephony.PhoneFactory"); Method m = c.getMethod("getServiceName", String.class, int.class); spreadTmService = (String) m .invoke(c, Context.TELEPHONY_SERVICE, 1); TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); imsi_1 = tm.getSubscriberId(); ... }。 [^3]: 引用[3]:读取SIM卡相关信息。if(short_str.equals("898600")||short_str.equals("898602")){String chanel="移动";}else if(short_str.equals("898601")){String chanel="电信";}else if(short_str.equals("898603")){String chanel="联通";}。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值