最近几天,因为项目需要,发彩信界面不再是调用系统的界面,即不跳转到短信界面,这个功能起初感觉应该很简单,但是真正做起来后,发现其实没有想象中那么简单,刚做完项目,趁头脑清晰,先把代码写下来先:
这几天为了这个项目,网上找了不少资料,大都资料都差不多,对于如何不跳用系统界面发彩信都有讲解,但是这个的前提是apn必须是wap,当如果是net时,因为连接超时而无法发送,正以内发彩信必须通过wap接入点才能发送,即使是在系统界面发彩信时,如果接入点不是wap,则会自动切换过来,待发送完后再切换回去,所以这个模块的核心,其实就是,如何在调用发彩信时,切换apn至wap,待发送完毕后再切换回去。。。
首先,根据不同移动供应商,需要设置不同的url和proxy
// 电信彩信中心url,代理,端口 public static String mmscUrl_ct = "http://mmsc.vnet.mobi"; public static String mmsProxy_ct = "10.0.0.200"; // 移动彩信中心url,代理,端口 public static String mmscUrl_cm = "http://mmsc.monternet.com"; public static String mmsProxy_cm = "010.000.000.172"; // 联通彩信中心url,代理,端口 public static String mmscUrl_uni = "http://mmsc.vnet.mobi"; public static String mmsProxy_uni = "10.0.0.172";
private static List<String> getSimMNC(Context context){ TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); String imsi = telManager.getSubscriberId(); if(imsi!=null){ ArrayList<String> list = new ArrayList<String>(); if(imsi.startsWith("46000") ||imsi.startsWith("46002")){ //因为移动网络编号46000下的IMSI已经用完,所以虚拟了一个46002编号,134/159号段使用了此编号 //中国移动 list.add(mmscUrl_cm); list.add(mmsProxy_cm); }else if(imsi.startsWith("46001")){ //中国联通 list.add(mmscUrl_uni); list.add(mmsProxy_uni); }else if(imsi.startsWith("46003")){ //中国电信 list.add(mmscUrl_ct); list.add(mmsProxy_ct); } shouldChangeApn(context); return list; } return null; }
当当前的apn接入点不是发彩信所需要的wap时,就需要切换:
private static boolean shouldChangeApn(final Context context){ final String wapId = getWapApnId(context); String apnId = getApn(context); //若当前apn不是wap,则切换至wap if(!wapId.equals(apnId)){ APN_NET_ID = apnId; setApn(context,wapId); //切换apn需要一定时间,先让等待2秒 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return true; } return false; }所有的apn信息都是存在数据表里,可以通过adb pull data/data/com.android.providers.telephony d:/ 直接拷出来,不过前提是手机有root权限:
private static String getApn(Context context){ ContentResolver resoler = context.getContentResolver(); String[] projection = new String[]{"_id"}; Cursor cur = resoler.query(Uri.parse("content://telephony/carriers/preferapn"),projection, null, null, null); String apnId = null; if(cur!=null&&cur.moveToFirst()){ do { apnId = cur.getString(cur.getColumnIndex("_id")); } while (cur.moveToNext()); } return apnId; } /** * 设置接入点 * @param id */ private static void setApn(Context context ,String id){ Uri uri = Uri.parse("content://telephony/carriers/preferapn"); ContentResolver resolver = context.getContentResolver(); ContentValues values = new ContentValues(); values.put("apn_id", id); resolver.update(uri, values, null, null); } private static String APN_NET_ID = null; /** * 取到wap接入點的id * @return */ private static String getWapApnId(Context context){ ContentResolver contentResolver = context.getContentResolver(); String[] projection = new String[]{"_id","proxy"}; Cursor cur = contentResolver.query(Uri.parse("content://telephony/carriers"), projection, "current = 1", null, null); if(cur!=null&&cur.moveToFirst()){ do { String id = cur.getString(0); String proxy = cur.getString(1); if(!TextUtils.isEmpty(proxy)){ return id; } } while (cur.moveToNext()); } return null; }取wap接入点的id方法中,就是从carriers表中读取到current=1的条目,只有这种条目能够显示在手机的apn设置中,即:
接下来这个方法,是处理发彩信请求:
private static boolean sendMMMS(List<String> list,final Context context, byte[] pdu) throws Exception { // HDR_AVLUE_ACCEPT_LANGUAGE = getHttpAcceptLanguage(); if(list==null){ myHandler.post(new Runnable() { @Override public void run() { Toast.makeText(context, "找不到sim卡", Toast.LENGTH_LONG).show(); } }); return false; } String mmsUrl = (String) list.get(0); String mmsProxy = (String) list.get(1); HttpClient client = null; try { URI hostUrl = new URI(mmsUrl); HttpHost target = new HttpHost(hostUrl.getHost(), hostUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME); client = AndroidHttpClient.newInstance("Android-Mms/2.0"); HttpPost post = new HttpPost(mmsUrl); ByteArrayEntity entity = new ByteArrayEntity(pdu); entity.setContentType("application/vnd.wap.mms-message"); post.setEntity(entity); post.addHeader(HDR_KEY_ACCEPT, HDR_VALUE_ACCEPT); post.addHeader(HDR_KEY_ACCEPT_LANGUAGE, HDR_VALUE_ACCEPT_LANGUAGE); HttpParams params = client.getParams(); HttpProtocolParams.setContentCharset(params, "UTF-8"); ConnRouteParams.setDefaultProxy(params, new HttpHost(mmsProxy, 80)); HttpResponse response = client.execute(target, post); StatusLine status = response.getStatusLine(); System.out.println("status : " + status.getStatusCode()); if (status.getStatusCode() != 200) { throw new IOException("HTTP error: " + status.getReasonPhrase()); } //彩信发送完毕后检查是否需要把接入点切换回来 if(null!=APN_NET_ID){ setApn(context,APN_NET_ID); } return true; } catch (Exception e) { e.printStackTrace(); Log.d(TAG, "彩信发送失败:"+e.getMessage()); //发送失败处理 } return false; }发彩信程序主入口:
private static String HDR_VALUE_ACCEPT_LANGUAGE = ""; private static final String HDR_KEY_ACCEPT = "Accept"; private static final String HDR_KEY_ACCEPT_LANGUAGE = "Accept-Language"; private static final String HDR_VALUE_ACCEPT = "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"; /** * 发彩信接口 by liuhanzhi * @param context * @param phone 手机号 * @param subject 主题 * @param text 文字 * @param imagePath 图片路径 * @param audioPath 音频路径 */ public static void send(final Context context,String phone,String subject,String text,String imagePath,String audioPath) { // String subject = "测试彩信"; Log.v("MmsTestActivity", subject); // String recipient = "18911722352";// 138xxxxxxx SendReq sendRequest = new SendReq(); EncodedStringValue[] sub = EncodedStringValue.extract(subject); if (sub != null && sub.length > 0) { sendRequest.setSubject(sub[0]); } EncodedStringValue[] phoneNumbers = EncodedStringValue .extract(phone); if (phoneNumbers != null && phoneNumbers.length > 0) { sendRequest.addTo(phoneNumbers[0]); } PduBody pduBody = new PduBody(); if(!TextUtils.isEmpty(text)){ PduPart partPdu3 = new PduPart(); partPdu3.setCharset(CharacterSets.UTF_8); partPdu3.setName("mms_text.txt".getBytes()); partPdu3.setContentType("text/plain".getBytes()); partPdu3.setData(text.getBytes()); pduBody.addPart(partPdu3); } if(!TextUtils.isEmpty(imagePath)){ PduPart partPdu = new PduPart(); partPdu.setCharset(CharacterSets.UTF_8); partPdu.setName("camera.jpg".getBytes()); partPdu.setContentType("image/png".getBytes()); // partPdu.setDataUri(Uri.parse("file://mnt//sdcard//.lv//photo//1326858009625.jpg")); partPdu.setDataUri(Uri.fromFile(new File(imagePath))); pduBody.addPart(partPdu); } if(!TextUtils.isEmpty(audioPath)){ PduPart partPdu2 = new PduPart(); partPdu2.setCharset(CharacterSets.UTF_8); partPdu2.setName("speech_test.amr".getBytes()); partPdu2.setContentType("audio/amr".getBytes()); // partPdu2.setContentType("audio/amr-wb".getBytes()); // partPdu2.setDataUri(Uri.parse("file://mnt//sdcard//.lv//audio//1326786209801.amr")); partPdu2.setDataUri(Uri.fromFile(new File(audioPath))); pduBody.addPart(partPdu2); } sendRequest.setBody(pduBody); final PduComposer composer = new PduComposer(context, sendRequest); final byte[] bytesToSend = composer.make(); final List<String> list = getSimMNC(context); Thread t = new Thread(new Runnable() { @Override public void run() { //因为在切换apn过程中需要一定时间,所以需要加上一个重试操作 int retry = 0; do { Log.d(TAG, "重试次数:"+(retry+1)); try { if (sendMMMS(list, context, bytesToSend)) { myHandler.post(new Runnable() { @Override public void run() { Toast.makeText(context, "彩信发送成功!", Toast.LENGTH_LONG).show(); } }); return; } retry++; Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } } while (retry < 5); myHandler.post(new Runnable() { @Override public void run() { Toast.makeText(context, "彩信发送失败!", Toast.LENGTH_LONG).show(); } }); } }); t.start(); }