关于android读取用户号码,手机串号,SIM卡序列号_移动Labs

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的,他用错了。

    <font color="#444444"><i>/**<br>     * Returns the serial number of the SIM, if applicable.<br>     * &lt;p&gt;<br>     * Requires Permission: <br>     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}<br>     */</i></font><br>    <strong>public</strong> <font color="#2040a0">String</font> <font color="#2040a0">getSimSerialNumber</font><font color="#4444ff"><strong>(</strong></font><font color="#4444ff"><strong>)</strong></font> <font color="#4444ff"><strong>{</strong></font><br>        <strong>try</strong> <font color="#4444ff"><strong>{</strong></font><br>            <strong>return</strong> <font color="#2040a0">getSubscriberInfo</font><font color="#4444ff"><strong>(</strong></font><font color="#4444ff"><strong>)</strong></font>.<font color="#2040a0">getSimSerialNumber</font><font color="#4444ff"><strong>(</strong></font><font color="#4444ff"><strong>)</strong></font><font color="#4444ff">;</font><br>        <font color="#4444ff"><strong>}</strong></font> <strong>catch</strong> <font color="#4444ff"><strong>(</strong></font><font color="#2040a0">RemoteException</font> <font color="#2040a0">ex</font><font color="#4444ff"><strong>)</strong></font> <font color="#4444ff"><strong>{</strong></font><br>        <font color="#4444ff"><strong>}</strong></font><br>        <strong>return</strong> <strong>null</strong><font color="#4444ff">;</font><br>    <font color="#4444ff"><strong>}</strong></font><br>2.相关几个定义、说明:<br>我们说到的和手机、卡相关的号码数据包括IMSI,MSISDN,ICCID,IMEI<br>IMSI:international mobiles subscriber identity国际移动用户号码标识,<br>这个一般大家是不知道,GSM必须写在卡内相关文件中;<br>MSISDN:mobile subscriber ISDN用户号码,这个是我们说的139,136那个号码;<br>ICCID:ICC identity集成电路卡标识,这个是唯一标识一张卡片物理号码的;<br>IMEI:international mobile Equipment identity手机唯一标识码;<br>

3.那好我们看看andorid实现TelephonyManager.java的源码:

getDeviceId()取IMEI号没有争议了。

/**

     * Returns the unique device ID, for example,the IMEI for GSM

     * phones.

     *

     * <p>Requires Permission:

     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}

     */

    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()去实现,我们下面找找看。

/**

     * Returns the phone number string for line 1, for example, the MSISDN

     * for a GSM phone.

     * <p>

     * Requires Permission:

     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}

     */

    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:

    /**

     * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones.

     */

    public String getDeviceId() {

        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, “Requires READ_PHONE_STATE”);

        return mPhone.getDeviceId();

    }

前面定义了Phone mPhone,再找Phone.java:

  /**

     * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones.

     */

    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

权限:公开   来自:labs

声明:

本文仅代表作者个人观点。其原创性及文中表达的意见、判断、数据、观点和陈述文字等内容均与中国移动研究院无关。移动Labs博客致力于为ICT领域的研究者及从业者提供技术和业务交流的网络平台,对本文中全部或部分内容的真实性、完整性不作任何保证或承诺,仅供读者参考交流。

来源URL:http://labs.chinamobile.com/mblog/427_62947