android系统不调用系统界面后台发送彩信的实现

最近做个业务系统,需要在android手机上通过代码后台发送个报告。其实一开始是用短信实现的,很简单,网上源码多的是。但有个问题:短信的长度是受限的,全是半角的话最多140个字符,如果有汉字或者全角字符,就变成63个。一份报告,会被拆分成好几条短信。但这还不是最严重的问题,更让人不可忍受的是:报告被拆分成几条短信后,虽然是顺序发送(这里指的是代码按拆分顺序将短信依次压入系统短信数据库),但其实发送的时候并不按照顺序来,或者说,从表象上看,接收方收到的短信基本不按顺序来,这使阅读报告时非常别扭,得人肉恢复顺序!这个确实不能忍。

后来想了想,大概有以下几种办法解决:

第一种:使用传说中的“长短信”协议发送短信。好像这玩意儿还得接收方支持。这个只听说过,没实际用过,直接pass了。

第二种:在接收方手机上内置一个专门的短信接收程序,说白了就是实现一套自己的“长短信”发送和接收协议。发送的时候在短信内部包含了短信标识(用此标识将用于发送报告的短信和普通短信区分开)、短信总数和短信编号。接收程序监听收到短信事件并对短信标识进行判断,只拦截用于发送报告的短信。在感兴趣的所有短信都收齐之后将内容提取出来生成完整的报告。这个也pass了。一来以前实现过这玩意儿,感觉也不是很好玩,另外,部署系统的时候还需要多安装一个程序,也不太喜欢。

第三种:用彩信发送报告。这个在长度上就基本没什么限制了,而且还能带多媒体数据。虽然目前只发送文本数据,但保不齐将来想添上图片、视频啥的。所以就决定用彩信了。

用彩信发送报告。动手之后才发现,事情远远不像想象的那么简单。主要是因为android从4.0(好像是)以后,已经不允许应用获得系统权限,这个限制造成要想发送彩信,只能通过系统自带的短信发送程序来实现。其实这个跟发短信就一样了,自己的代码生成彩信,调用api将其压入系统彩信数据库。系统中内置的彩信发送应用轮询到以后将彩信取出然后发送出去。也就是说,所谓的“后台发送”,只能在4.0以下实现,更高版本都报“没有权限”的错误。网上的帖子都是这个路子。

在csdn上发帖子问了几天,可能因为是过年吧,没人理我。自己每天上去顶一次,也没效果,呵呵,就只能自力更生了。


google想办法,这种事儿,baidu就无能为力了:)。弄了几天终于基本上实现了。下面大概说下细节。


开发环境用的是eclipse+adt。

实现方法参考了几个帖子:

http://www.cnblogs.com/rayray/archive/2013/03/18/Android_MMS.html

这些帖子中涉及到以下几个库、项目:

droidprism.jar

jsoup.jar

GitHub上的项目https://github.com/klinker41/android-smsmms(这里简称为‘项目X’)


从目前个人的理解上,这种方法的核心在于彩信实际上是一种带有特殊格式的email,因此,需要做的就是正确构造这个email,并且能够获取发送通道和目的地。因为细节还没完全弄清楚,所以就只说明怎么做了。

1、创建一个android app项目(就叫SendMMS吧),弄个主Activity,放一个Send按钮上去之类的。这属于准备工作了。

2、将项目X的源码下载下来并导入到eclipse中。需要注意的是导入后其实是两个项目,都是库。将它们都加入SendMMS项目中。


3、在SendMMS项目的构建路径上添加droidprism.jar和jsoup.jar,并在“排序和导出”选项卡中将它们打上勾。



4、给SendMMS项目添加权限

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_MMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.SEND_MMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_SMS" />
    <uses-permission android:name="android.provider.Telephony.SMS_RECEIVED" />


5、import部分

import com.droidprism.APN;
import com.droidprism.Carrier;
import com.klinker.android.send_message.Message;
import com.klinker.android.send_message.Settings;
import com.klinker.android.send_message.Transaction;

6、发送代码。以下是用一个线程发送彩信的代码,直接在Send按钮的点击事件中调用即可。

注意:

1、不需要参数imagePath、audioPath时,不要用null,而要用“”。其实,我还没试验过这俩参数......

2、要把手机“移动网络”中的“启用数据网络”打开。如果没打开,那么彩信将无法立即发送。打开后会自动发送出去;


	private void sendMMS(final Context context, final String phone, final String subject, final String message, String imagePath, String audioPath)
	{
		new Thread()
		{
			@Override
			public void run()
			{
				try
				{
					Carrier carrier = null;
					APN apn = null;
					Settings sendSettings = new Settings();
					TelephonyManager tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
					String networkOperator = tel.getNetworkOperator();
					if (networkOperator != null)
					{
						int mcc = Integer.parseInt(networkOperator.substring(0, 3));
						String s = networkOperator.substring(3);
						int mnc = Integer.parseInt(s);
						carrier = Carrier.getCarrier(mcc, mnc);
						carrier.getsmsemail();
						apn = carrier.getAPN();
					}

					sendSettings.setMmsc(apn.mmsc);
					sendSettings.setProxy(apn.proxy);
					sendSettings.setPort(Integer.valueOf(apn.port).toString());
					sendSettings.setGroup(true);
					sendSettings.setDeliveryReports(false);
					sendSettings.setSplit(false);
					sendSettings.setSplitCounter(false);
					sendSettings.setStripUnicode(false);
					sendSettings.setSignature("");
					sendSettings.setSendLongAsMms(true);
					sendSettings.setSendLongAsMmsAfter(3);
					sendSettings.setRnrSe(null);
					Transaction sendTransaction = new Transaction(instance, sendSettings);
					Message mMessage = new Message(message, phone);
					mMessage.setSubject(subject);
					mMessage.setType(Message.TYPE_SMSMMS);
					sendTransaction.sendNewMessage(mMessage, 0);
				} catch (Exception e)
				{
					e.printStackTrace();
				}
			};
		}.start();
	}

遗留问题:

1、从项目X的说明中看,它目前还处于beta状态,不是很稳定。使用中也发现似乎缺一些异常处理的部分,所以发送时会报错,出那个“应用已经停止运行”的框框,但经过几十次测试,虽然报错但不影响发送。猜测可能会影响对发送结果的检测,这个还没仔细研究;

2、目前还没研究获取发送结果的代码,同时,发送后会在发件箱里留有一个副本。如果要自动删除副本的话,需要在获取发送结果后进行操作;

3、还没仔细研究引用库和项目的License;

4、还在寻找更好的办法;



评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值