android 自定义发彩信实现(不调用系统发彩信界面)

最近几天,因为项目需要,发彩信界面不再是调用系统的界面,即不跳转到短信界面,这个功能起初感觉应该很简单,但是真正做起来后,发现其实没有想象中那么简单,刚做完项目,趁头脑清晰,先把代码写下来先:

这几天为了这个项目,网上找了不少资料,大都资料都差不多,对于如何不跳用系统界面发彩信都有讲解,但是这个的前提是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();

	}



评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值