这篇讲一下获取用户的手机号为用户 ID,用来 POST 到服务端。
刚开始弄的时候想获取手机,想着用自带的 TelephonyManager 获取手机的相关信息。结果进了一个坑,最后发现用不了。先讲一下过程。
首先,获取手机号等信息需要申明权限。
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
然后为了方便,写了一个 Util 类,方便调用。
package com.yyxt.jireh.gpst2.Util; import android.content.Context; import android.telephony.TelephonyManager; /** * 2017年8月25日 10:10:58 * Jireh * www.lyile.cn * admin@lyile.cn * 获取手机相关信息1 **/ public class PhoneInfo { private TelephonyManager telephonyManager; /** * 国际移动用户识别码 */ private String IMSI; private Context cxt; public PhoneInfo(Context context) { cxt=context; telephonyManager = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); } /** * 获取电话号码 */ public String getNativePhoneNumber() { String NativePhoneNumber=null; NativePhoneNumber=telephonyManager.getLine1Number(); return NativePhoneNumber; } /** * 获取手机服务商信息 */ public String getProvidersName() { String ProvidersName = "N/A"; try{ IMSI = telephonyManager.getSubscriberId(); // IMSI号前面3位460是国家,紧接着后面2位00 02是中国移动,01是中国联通,03是中国电信。 System.out.println(IMSI); if (IMSI.startsWith("46000") || IMSI.startsWith("46002")) { ProvidersName = "中国移动"; } else if (IMSI.startsWith("46001")) { ProvidersName = "中国联通"; } else if (IMSI.startsWith("46003")) { ProvidersName = "中国电信"; } }catch(Exception e){ e.printStackTrace(); } return ProvidersName; } public String getPhoneInfo(){ TelephonyManager tm = (TelephonyManager)cxt.getSystemService(Context.TELEPHONY_SERVICE); StringBuilder sb = new StringBuilder(); sb.append("\nDeviceId(IMEI) = " + tm.getDeviceId()); sb.append("\nDeviceSoftwareVersion = " + tm.getDeviceSoftwareVersion()); sb.append("\nLine1Number = " + tm.getLine1Number()); sb.append("\nNetworkCountryIso = " + tm.getNetworkCountryIso()); sb.append("\nNetworkOperator = " + tm.getNetworkOperator()); sb.append("\nNetworkOperatorName = " + tm.getNetworkOperatorName()); sb.append("\nNetworkType = " + tm.getNetworkType()); sb.append("\nPhoneType = " + tm.getPhoneType()); sb.append("\nSimCountryIso = " + tm.getSimCountryIso()); sb.append("\nSimOperator = " + tm.getSimOperator()); sb.append("\nSimOperatorName = " + tm.getSimOperatorName()); sb.append("\nSimSerialNumber = " + tm.getSimSerialNumber()); sb.append("\nSimState = " + tm.getSimState()); sb.append("\nSubscriberId(IMSI) = " + tm.getSubscriberId()); sb.append("\nVoiceMailNumber = " + tm.getVoiceMailNumber()); return sb.toString(); } }
然后在就可以在 Activite 中添加调用代码。
PhoneInfo phoneinfo= new PhoneInfo(MainActivity.this); Log.d("MainActivity***********This is NativePhoneNumber",phoneinfo.getNativePhoneNumber());
但是发现这样其实,并没用获取到手机号码等相关的信息。这是因为 getNativePhoneNumber 获取的是你手机 sim 卡当中的信息,但是现在的运营商并没有把手机号信息写入 Sim 卡当中。但是你可以先获取手机 imei 号作为它的识别码来用,而且双卡手机获取用这样的方法也是获取不到或者是只能获取到其中的一条。 如果有机会,我会拉一片扩展篇来讲一下,怎么处理适配双卡手机的信息收集。
因为上面的 getNativePhoneNumber 方式不行,所以只能用,在输入框中输入手机号信息。当然也不是一定没有其他方式,其实后面我还想出了一个方式来获取手机号码,就是通过发送短信来获取手机号,比如移动发送:本机号码就可以自己的手机号码。这种方式双卡手机也可以适用,匹配卡槽来发送短信并检测。
当然目前用的是输入框的方式
在 layout 中添加一个输入框和提交按钮
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" android:focusable="true" android:focusableInTouchMode="true" > <Button android:id="@+id/startServBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/startServ" android:layout_below="@+id/phoneTextEdit" android:layout_alignParentLeft="true" android:layout_alignParentStart="true"/> <Button android:id="@+id/endServBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/endServ" android:layout_below="@+id/startServBtn" android:layout_alignRight="@+id/endApp" android:layout_alignEnd="@+id/endApp" android:visibility="gone"/> <Button android:id="@+id/endApp" android:layout_alignParentBottom="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/endApp" android:visibility="invisible"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/phoneTextEdit" android:textAlignment="textEnd" android:textStyle="bold" android:hint="请先输入手机号码" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true"/> <TextView android:id="@+id/content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/gpsData" android:maxLines="22" android:scrollbars="vertical" android:layout_below="@+id/startServBtn" android:layout_alignParentLeft="true" android:layout_alignParentStart="true"/> <Button android:text="提交" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/phoneSubmit" android:layout_below="@+id/phoneTextEdit" android:layout_alignParentRight="true" android:layout_alignParentEnd="true"/> </RelativeLayout>
然后在 Activite 中添加输入框和按钮,并添加按钮事件。在这里我用的保存方式为 SharedPreferences 的方式,这种方式的比较方便,存储一些较简单的数据这里用的是调用 Context 对象的 getSharedPreferences()方法,这样的话 getSharedPreferences()方法获得的 SharedPreferences 对象可以被同一应用程序下的其他组件共享。而 Activity 对象的 getPreferences()方法获得的 SharedPreferences 对象只能在该 Activity 中使用。
package com.yyxt.jireh.gpst2; import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.*; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.alo7.android.update.UpdateAgent; import pub.devrel.easypermissions.EasyPermissions; import java.util.List; import static android.content.ContentValues.TAG; public class MainActivity extends Activity implements EasyPermissions.PermissionCallbacks{ private static final String LOCSTART = "START_LOCATING"; private Button phoneSubmitBtn; private Button startBtn; private Button endBtn; private Button endApp; private TextView phoneTip; private TextView content; private EditText phoneEdit; private LocationReceiver lr; private AlarmManager alarmManager; private PendingIntent pi; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); UpdateAgent.setConfigUrl("http://120.199.120.92/js/config.json"); setContentView(R.layout.activity_main); Log.i("MainActivity", "********MainActivity onCreate*******"); phoneSubmitBtn=(Button) findViewById(R.id.phoneSubmit); phoneEdit=(EditText) findViewById(R.id.phoneTextEdit); startBtn = (Button) findViewById(R.id.startServBtn); endBtn = (Button) findViewById(R.id.endServBtn); endApp = (Button) findViewById(R.id.endApp); phoneTip=(TextView) findViewById(R.id.phoneTip); content = (TextView) findViewById(R.id.content); content.setMovementMethod(ScrollingMovementMethod.getInstance()); alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE); final SharedPreferences ph = getSharedPreferences("phoneNumber",MODE_PRIVATE);//在开始的时候调用创建ph 设置操 作模式 endBtn.setVisibility(8); if (ph.getString("phoneID","none").length()==11){ //判断配置文件中的手机号是否存在,判断第一次使用 phoneEdit.setText(ph.getString("phoneID","none")); phoneEdit.setEnabled(false); phoneTip.setVisibility(8); phoneSubmitBtn.setVisibility(4); content.setVisibility(0); }else{ startBtn.setVisibility(View.INVISIBLE); //gone 8不显示不占空间 visible 0正常 nvisible 4不显示 phoneEdit.setEnabled(true); phoneSubmitBtn.setVisibility(0); content.setVisibility(4); Toast.makeText(getApplicationContext(), "请先输入手机号码否则将无法使用", Toast.LENGTH_SHORT).show(); } startBtn.setOnClickListener(new View.OnClickListener() { @TargetApi(Build.VERSION_CODES.M) @Override public void onClick(View arg0) { Log.i("MainActivity", "********MainActivity startBtn onClick*******"); Intent intent = new Intent(LOCSTART); pi = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10000, pi); Toast.makeText(getApplicationContext(), "GPS测试开始"+ph.getString("phoneID","none"), Toast.LENGTH_SHORT).show(); } }); phoneSubmitBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.i("MainActivity","*********MainActivity phoneSubmit onClick*******"); String phone =phoneEdit.getText().toString().trim(); SharedPreferences.Editor editor =ph.edit(); //使用配置文件方式保存手机号 if (phone.length()!=11){ Toast.makeText(getApplicationContext(), "手机号码格式不正确或者为空,请重新输入", Toast.LENGTH_SHORT).show(); }else{ editor.putString("phoneID",phone);//存入手机号到,phoneID下载 editor.commit();//提交保存操作 startBtn.setVisibility(0); phoneTip.setVisibility(8); phoneEdit.setEnabled(false); phoneSubmitBtn.setVisibility(4); content.setVisibility(0); Toast.makeText(getApplicationContext(), "手机号设置成功", Toast.LENGTH_SHORT).show(); } } }); endBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub Log.i("MainActivity", "********MainActivity endBtn onClick*******"); alarmManager.cancel(pi); Intent intent = new Intent(LOCSTART); stopService(intent); Toast.makeText(getApplicationContext(), "GPS测试结束", Toast.LENGTH_SHORT).show(); } }); endApp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub android.os.Process.killProcess(android.os.Process.myPid()); } }); lr = new LocationReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("NEW LOCATION SENT"); registerReceiver(lr, intentFilter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.i("MainActivity", "********MainActivity onDestroy*******"); unregisterReceiver(lr); } }
补充下 SharedPreferences 有四种的操作模式。
MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取。
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
最后用获取到的手机为主键,获取经纬度 Post 服务端。因为是想实时获取,所以直接就在 BDGpsServiceListener 中实现
package com.yyxt.jireh.gpst2; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; import android.telephony.TelephonyManager; import android.util.Log; import com.baidu.location.BDLocation; import com.baidu.location.BDLocationListener; import com.google.gson.Gson; import com.yyxt.jireh.gpst2.GsonBean.SetingBean; import com.yyxt.jireh.gpst2.Util.HttpUtil; import com.yyxt.jireh.gpst2.Util.PhoneInfo; import org.json.JSONException; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import static android.content.Context.MODE_PRIVATE; public class BDGpsServiceListener implements BDLocationListener { private Context context; public PhoneInfo phoneInfo; private TelephonyManager telephonyManager; private Context cxt; private String phid; private String Result; private int start_hour; private int start_minutes; private int end_hour; private int end_minutes; public BDGpsServiceListener(){ super(); } public BDGpsServiceListener(Context context){ super(); this.context = context; cxt=context; telephonyManager = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); SharedPreferences ph = context.getSharedPreferences("phoneNumber",MODE_PRIVATE); phid=ph.getString("phoneID","none"); } //发送广播,提示更新界面 private void sendToActivity(String str){ Intent intent = new Intent(); intent.putExtra("newLoca", str); intent.setAction("NEW LOCATION SENT"); context.sendBroadcast(intent); } @Override public void onReceiveLocation(BDLocation location) { // TODO Auto-generated method stub Log.i("Listener", "********BDGpsServiceListener onReceiveLocation*******"); //TelephonyManager tm = (TelephonyManager)cxt.getSystemService(Context.TELEPHONY_SERVICE); Date date = new Date(); StringBuffer sb = new StringBuffer(); try { try { String AllJsonData = HttpUtil.getRequest("http://120.199.120.92/ashx/location.ashx?t=7"); Log.i("Listener", "JsonData : "+AllJsonData); Gson gson = new Gson(); SetingBean r = gson.fromJson(AllJsonData, SetingBean.class); if (r.getState()==1){ start_hour=r.getParma().getStart_hour(); start_minutes=r.getParma().getStart_minute(); end_hour=r.getParma().getEnd_hour(); end_minutes=r.getParma().getEnd_minute(); } Log.i("Listener", r.getState()+"state"); } catch (JSONException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }catch (Exception e) { e.printStackTrace(); } if(location == null){return;} sb.append("经度=").append(location.getLongitude()); sb.append("\n纬度=").append(location.getLatitude()); sb.append("\n时间=").append(location.getTime()); sb.append("\n运营商=").append(location.getOperators()); sb.append("\nERR Code=").append(location.getLocType()); sb.append("\n手机型号:").append(android.os.Build.MODEL); if (location.hasRadius()){ sb.append("\n定位精度=").append(location.getRadius()); } if (location.getLocType() == BDLocation.TypeGpsLocation){ sb.append("\n速度="); sb.append(location.getSpeed()); sb.append("\n卫星="); sb.append(location.getSatelliteNumber()); } else if (location.getLocType() == BDLocation.TypeNetWorkLocation){ sb.append("\n位置=").append(location.getAddrStr()); sb.append("\n省=").append(location.getProvince()); sb.append("\n市=").append(location.getCity()); sb.append("\n市Code=").append(location.getCityCode()); sb.append("\n区县=").append(location.getDistrict()); } try {//Post数据 Map<String,String> map = new HashMap<String, String>(); map.put("lng", location.getLongitude()+""); map.put("lat", location.getLatitude()+""); //map.put("time", location.getTime()+""); map.put("mobile",phid);// get phone String url = HttpUtil.BASE_URL; Result=HttpUtil.postRequest(url, map); } catch (Exception e) { e.printStackTrace(); } Log.d("BDGpsServiceListener","***********Result************"+Result); sb.append("\n============\nResult:").append(Result); } sendToActivity(sb.toString()); } }
这里调用的是写的一个 HttpUtil 类,包含 Post 和 Get。
package com.yyxt.jireh.gpst2.Util; /** * 2017年8月25日 10:10:58 * Jireh * www.lyile.cn * admin@lyile.cn * HttpUitl类,post和get数据 **/ import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class HttpUtil { //创建HttpClient对象 public static HttpClient httpClient = new DefaultHttpClient(); public static final String BASE_URL = "http://120.199.120.92/ashx/location.ashx?t=6"; public static String submitPostData(String strUrlPath,Map<String, String> params, String encode) { byte[] data = getRequestData(params, encode).toString().getBytes();//获得请求体 try { //String urlPath = "http://192.168.1.9:80/JJKSms/RecSms.php"; URL url = new URL(strUrlPath); HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection(); httpURLConnection.setConnectTimeout(3000); //设置连接超时时间 httpURLConnection.setDoInput(true); //打开输入流,以便从服务器获取数据 httpURLConnection.setDoOutput(true); //打开输出流,以便向服务器提交数据 httpURLConnection.setRequestMethod("POST"); //设置以Post方式提交数据 httpURLConnection.setUseCaches(false); //使用Post方式不能使用缓存 //设置请求体的类型是文本类型 httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //设置请求体的长度 httpURLConnection.setRequestProperty("Content-Length", String.valueOf(data.length)); //获得输出流,向服务器写入数据 OutputStream outputStream = httpURLConnection.getOutputStream(); outputStream.write(data); int response = httpURLConnection.getResponseCode(); //获得服务器的响应码 if(response == HttpURLConnection.HTTP_OK) { InputStream inptStream = httpURLConnection.getInputStream(); return dealResponseResult(inptStream); //处理服务器的响应结果 } } catch (IOException e) { //e.printStackTrace(); return "err: " + e.getMessage().toString(); } return "-1"; } /* * Function : 封装请求体信息 * Param : params请求体内容,encode编码格式 */ public static StringBuffer getRequestData(Map<String, String> params, String encode) { StringBuffer stringBuffer = new StringBuffer(); //存储封装好的请求体信息 try { for(Map.Entry<String, String> entry : params.entrySet()) { stringBuffer.append(entry.getKey()) .append("=") .append(URLEncoder.encode(entry.getValue(), encode)) .append("&"); } stringBuffer.deleteCharAt(stringBuffer.length() - 1); //删除最后的一个"&" } catch (Exception e) { e.printStackTrace(); } return stringBuffer; } /* * Function : 处理服务器的响应结果(将输入流转化成字符串) * Param : inputStream服务器的响应输入流 */ public static String dealResponseResult(InputStream inputStream) { String resultData = null; //存储处理结果 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = 0; try { while((len = inputStream.read(data)) != -1) { byteArrayOutputStream.write(data, 0, len); } } catch (IOException e) { e.printStackTrace(); } resultData = new String(byteArrayOutputStream.toByteArray()); return resultData; } public static String getRequest(final String url) throws Exception{ FutureTask<String> task = new FutureTask<String>(new Callable<String>() { @Override public String call() throws Exception { // 创建HttpGet对象 HttpGet get = new HttpGet(url); //发送get请求 HttpResponse httpResponse = httpClient.execute(get); //如果服务器成功地返回响应 if(httpResponse.getStatusLine().getStatusCode() == 200){ //获取服务器响应字符串 String result = EntityUtils.toString(httpResponse.getEntity()); return result; } return null; } }); new Thread(task).start(); return task.get(); } public static String postRequest(final String url, final Map<String,String> rawParams) throws Exception{ FutureTask<String> task = new FutureTask<String>(new Callable<String>() { @Override public String call() throws Exception { // 创建HttpPost对象 HttpPost post = new HttpPost(url); //如果传递的参数个数比较多,可以对传递的参数进行封装 List<NameValuePair> params = new ArrayList<NameValuePair>(); for(String key:rawParams.keySet()){ //封装请求参数 params.add(new BasicNameValuePair(key, rawParams.get(key))); } //设置请求参数 post.setEntity(new UrlEncodedFormEntity(params,"utf-8")); //发送post请求 HttpResponse httpResponse = httpClient.execute(post); //如果服务器成功地返回响应 if(httpResponse.getStatusLine().getStatusCode() == 200){ //获取服务器响应字符串 String result = EntityUtils.toString(httpResponse.getEntity()); return result; } return null; } }); new Thread(task).start(); return task.get(); } }