最近一轮迭代改成了用验证码的方式去获取手机号,所以这个方案也没有意义了,权当作记录吧。
Android本机号码手机与提交方案
一、背景:
1、能直接获取号码:
TelephonyManager tm = (TelephonyManager)this. getSystemService( Context.TELEPHONY_SERVICE);
String deviceid = tm.getDeviceId();
String tel = tm.getLine1Number();//手机号码
String imei = tm.getSimSerialNumber();
String imsi = tm.getSubscriberId();
能直接获取到tel,这件事情就算完了。
2、得向运营商查询:
简单说就是:国内运营商们采用了一种先进的技术,把电话号码和SIM卡分离,部分新手机卡,电话号码不能从SIM获得。(SIM卡唯一的识别标志是IMSI码。)
3、WAP获取手机号:http://wap.10086.cn/ywcx/zdcx.jsp
以移动为例,CMWAP用的是移动的内网,手机请求通过网关时,网关对请求的head部分注入当前手机号。注入的这个手机号只有被授权的SP服务商之类的才能看到。
很多网站宣传能有40~60%的概率获取手机号就是用WAP的用户比例大概为40~60%,一般在网站后台做识别处理输出。
二、完整的方案可能是:
ü 获取手机号:
A、短信、电话查询运营商,截获短信。读取短信,获取短信记录中,当前时间戳内可信的电话号码。把号码和IMSI存进SharedPreferences或者文件中。
B、查看用户是不是使用流量,是不是使用WAP,切换到WAP,关闭wifi,模拟打开10086 wap网站,获取上面显示的号码,把号码和IMSI存进缓存中,切换回原来的通讯方式
C、用手机发短信,短信内容是当前号码的IMSI到短信机,每次登陆、退出登陆都用IMSI和后台通讯
ü 获取已存储的手机号:
1、查询SIM有没有手机号码?
2、查询是否有缓存电话号码记录?
ü 更新手机号:
1、登陆时向后台更新电话号码
2、退出登陆时清除电话号码
三、具体实现
用第一种方式处理。一次获取本机号码的过程如下:
1、检测是否有SIM卡(有IMSI号码)
TelephonyManager iTelephonyMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
String IMSI = iTelephonyMgr.getSubscriberId();
if(IMSI == null || IMSI.length() == 0){return false;}
2、检测是都有缓存:
String key = getIMSIKey(context);
return CAppDataModel.GetStaticString(key,"");
private String getIMSIKey(Context context){
TelephonyManager mTelephonyMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
String imsi = mTelephonyMgr.getSubscriberId();
if(imsi != null && imsi.length() != 0){
return ConstVal.CGlobalKey.SIM_IMSI_PREFIX + imsi;
}
return "";
}
3、 判断运营商:
private boolean MarkSimOperator(){
String operator = iTelephonyMgr.getSimOperator();
if(operator != null){
if(operator.equals("46000") || operator.equals("46002")|| operator.equals("46007")){
SimOperator = 0x0001;//移动
}else if(operator.equals("46001")){
SimOperator = 0x0002;//联通
}else if(operator.equals("46003")){
SimOperator = 0x0004;//电信
}
}
return SimOperator != 0;//is mark success
}
4、获取SIM卡上固化的电话号码:
String Phone = iTelephonyMgr.getLine1Number();
5、获取不到发短信:
SmsManager manage=SmsManager.getDefault();
PendingIntent sentIntent = PendingIntent.getBroadcast(refer, 0,new Intent(), 0);
manage.sendTextMessage(getAddress(), null, getMessage(), sentIntent,null);
6、定期检查短信(6s查一次,查60次)
private String readSmsDataBaseToGetPhone(Context context){
String address = getAddress();
Sms objSms = new Sms();
Uri message = Uri.parse("content://sms/inbox");
Cursor c = context.getContentResolver().query(message, null,null,null,"date DESC");
int totalSMS = c.getCount();
if (c.moveToFirst()) {
for (int i = 0; i < totalSMS; i++) {
objSms = new Sms();
objSms.setAddress(c.getString(c.getColumnIndexOrThrow("address")));
objSms.setMsg(c.getString(c.getColumnIndexOrThrow("body")));
objSms.setReadState(c.getString(c.getColumnIndex("read")));
objSms.setTime(c.getString(c.getColumnIndexOrThrow("date")));
if(c.getString(c.getColumnIndexOrThrow("date")).compareTo(StackTop) <= 0){
c.close();
return "";
}
if(objSms.is(address)){
String str = objSms.getPhoneFromMessage(getMessageMacher());
if(Number.isNumeric(str)){
c.close();
return str;
}
}
c.moveToNext();
}
}
c.close();
return "";
}
备注1:StackTop是我获取的时间戳,即发短信前,短信数据库最近一次收到短信的时间。数据库输出按时间排序
备注2:EnsurePhoneNumExited()函数会 重复1~6的步骤
上述过程中有一个步骤获取到号码,或者是检查到无SIM卡,或者是SIM卡中有号码即退出
流程图如下:(略)
四、解释问题:
要解释清楚几个容易出错的问题处理:
1.每个运营商都有2个指令,什么情况下会切换使用
不幸的是,目前只有联通找到两个指令,每次发完信息后,我会记住发信息的次数,按当前发信息的次数是奇书、偶数来切换指令,具体代码如下:
2.短信内容解析提取号码的方法是什么?
关键字匹配 + 号码长度匹配
Macher = new String[]{"流量","剩余"};
public String getPhoneFromMessage(String[] macher){
if(macher == null || _msg ==null || _msg.length() == 0){return NULL;}
for(String ms:macher){// 关键字匹配
if(!_msg.contains(ms)){return NULL; }
}
String[] nums = _msg.split("\\D+");
for(String s:nums){ //号码长度要求
if(s.length() >= MinPhoneLength){
return s;
}
}
return NULL;
}
关键字:我们发信息查指令,运营商返回的信息必然会包括一些特殊关键字。但在等待回执过程中,可能运营商会回复一些垃圾短信、多个号码的短信,必须过滤掉这些东西。
3.什么时候需要发送短信获取号码
当 “有SIM卡&&获取不到用IMSI码作为键值的缓存号码&& SIM卡中没有固化手机号码”
4.怎么判断双卡双待:
这个问题是我想多了。原生Android的设计只有单卡,双卡是国内的杰作。所以国内区分了主卡和次卡的概念。用android api获取到的是主卡,次卡得用反射才能拿到。只有一张卡时,那张卡被系统默认为主卡,现在的处理是不管有没有次卡,直接用主卡去匹配。
5.兼容性问题:
有些手机,例如 小米,明明有信息过来,就是读不到短信内容,是因为第三方rom修改了sms的contentProvider,只允许应用读那些非验证码的信息,遇到这种情况,获取手机号码就失败了。
Yeshen in Landowsoft
2015.11.24