Android 开发之旅:短信的收发及在android模拟器之间实践(一)

简介:



本文转自吴秦博客园博客,原文链接:http://www.cnblogs.com/skynet/archive/2010/06/14/1758284.html,如需转载请自行联系原作者引言

本文通过运行两个Android模拟器,介绍在Android中如何实现短信服务(SMS,short message service)的功能。通过这个例子,我想带给大家的是:更加熟悉之前介绍过的Android应用程序的概念及技术细节,且通过实例调度大家的兴趣。我之所以选择SMS为例子,主要原因是SMS已经非常成熟了,从中可以发掘更多的信息和技术细节,而且我相信大部分人发短信比打电话多。

本文的主要内容如下:

  • 1、温故知新
  • 2、准备工作:SMS涉及的主要类SmsManager
  • 3、简单的SMS发送程序
    • 3.1、运行SMS程序给另一个android模拟器发短
  • 4、SMS增强(一)
  • 5、SMS增强(二)
  • 6、SMS接收程序(下篇)
  • 7、emulator工具(下篇)
  • 8、…

1、温故知新

广播接收者:一个广播接收者是这样一个组件,它不做什么事,仅是接受广播公告并作出相应的反应。许多广播源自于系统代码,例如公告时区的改变、电池电量低、已采取图片、用户改变了语言偏好。应用程序也可以发起广播,例如为了他其他程序知道某些数据已经下载到设备且他们可以使用这些数据

BroadcastReceiver类:是接受sendBroadcast()发送的意图(intents)的基类。可以用Context.registerReceiver()动态地注册这个类的实例,或者通过AndroidManifest.xml中<receiver>标签静态发布。

广播接收者不显示一个用户界面。然而,它们启动一个活动去响应收到的信息,或者他们可能使用NotificationManager去通知用户。通知可以使用多种方式获得用户的注意——闪烁的背光、振动设备、播放声音等等。典型的是放在一个持久的图标在状态栏,用户可以打开获取信息。

2、准备工作:SMS涉及的主要类SmsManager

实现SMS主要用到SmsManager类,该类继承自java.lang.Object类,下面我们介绍一下该类的主要成员。

公有方法:

  • ArrayList<String> divideMessage(String text)
    当短信超过SMS消息的最大长度时,将短信分割为几块。
    参数text——初始的消息,不能为空
    返回值:有序的ArrayList<String>,可以重新组合为初始的消息
  • static SmsManager getDefault()
    获取SmsManager的默认实例。
    返回值SmsManager的默认实例
  • void SendDataMessage(String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)
    发送一个基于SMS的数据到指定的应用程序端口。
    参数
    1)、destinationAddress——消息的目标地址
    2)、scAddress——服务中心的地址or为空使用当前默认的SMSC 3)destinationPort——消息的目标端口号
    4)、data——消息的主体,即消息要发送的数据
    5)、sentIntent——如果不为空,当消息成功发送或失败这个PendingIntent就广播。结果代码是Activity.RESULT_OK表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU之一表示错误。对应RESULT_ERROR_GENERIC_FAILURE,sentIntent可能包括额外的“错误代码”包含一个无线电广播技术特定的值,通常只在修复故障时有用。
    每一个基于SMS的应用程序控制检测sentIntent。如果sentIntent是空,调用者将检测所有未知的应用程序,这将导致在检测的时候发送较小数量的SMS。
    6)、deliveryIntent——如果不为空,当消息成功传送到接收者这个PendingIntent就广播。
    异常:如果destinationAddressdata是空时,抛出IllegalArgumentException异常。
  • void sendMultipartTextMessage(String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliverIntents)
    发送一个基于SMS的多部分文本,调用者应用已经通过调用divideMessage(String text)将消息分割成正确的大小。
    参数
    1)、destinationAddress——消息的目标地址
    2)、scAddress——服务中心的地址or为空使用当前默认的SMSC
    3)、parts——有序的ArrayList<String>,可以重新组合为初始的消息
    4)、sentIntents——跟SendDataMessage方法中一样,只不过这里的是一组PendingIntent
    5)、deliverIntents——跟SendDataMessage方法中一样,只不过这里的是一组PendingIntent
    异常:如果destinationAddressdata是空时,抛出IllegalArgumentException异常。
  • void sendTextMessage(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)
    发送一个基于SMS的文本。参数的意义和异常前面的已存在的一样,不再累述。

常量:

  • public static final int RESULT_ERROR_GENERIC_FAILURE
    表示普通错误,值为1(0x00000001)
  • public static final int RESULT_ERROR_NO_SERVICE
    表示服务当前不可用,值为4 (0x00000004)
  • public static final int RESULT_ERROR_NULL_PDU
    表示没有提供pdu,值为3 (0x00000003)
  • public static final int RESULT_ERROR_RADIO_OFF
    表示无线广播被明确地关闭,值为2 (0x00000002)
  • public static final int STATUS_ON_ICC_FREE
    表示自由空间,值为0 (0x00000000)
  • public static final int STATUS_ON_ICC_READ
    表示接收且已读,值为1 (0x00000001)
  • public static final int STATUS_ON_ICC_SENT
    表示存储且已发送,值为5 (0x00000005)
  • public static final int STATUS_ON_ICC_UNREAD
    表示接收但未读,值为3 (0x00000003)
  • public static final int STATUS_ON_ICC_UNSENT
    表示存储但为发送,值为7 (0x00000007)

3、简单的SMS发送程序

1)、首先,编辑布局文件res/layout/main.xml,达到我们想要的结果,界面如下:

image

图1、程序运行界面

对应的xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
	android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <TextView android:layout_width="fill_parent"
			android:layout_height="wrap_content" 
			android:text="@string/txtPhoneNo"/>
    <!-- text's value define in res/values/strings.xml -->
    
    <EditText android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:id="@+id/edtPhoneNo"/>
	
    <TextView android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:text="@string/txtContent"/>
    
    <EditText android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:minLines="3"
			android:id="@+id/edtContent"/>
   
    <Button android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:text="@string/btnText"
			android:id="@+id/btnSend"/>
</LinearLayout>

相应的要在res/values/strings.xm中添加上面定义的视图的text的值,如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="txtPhoneNo">Please input phone NO:</string>
    <string name="txtContent">Please input SMS\'s content:</string>
    <string name="btnText">send!</string>
    <string name="app_name">SMS</string>
</resources>

2)、做完这些准备工作之后,我么要开始编写代码实现简单的短信发送了。

通过第一步我们构建好界面之后,现在要在上面的基础上编写业务逻辑了。大致过程为:在java源文件中,获取用户在edtPhoneNo中输入的电话号码,edtContent中输入要发送的内容;然后点击btnSend按钮发送短信,要达到这个目的我们要设置btnSend的OnClickListener以达到当点击它触发发送短信的功能,而且要发送短信就要用到我们前面介绍的SmsManager类提供的方法接口。

设置btnSend的OnClickListener的代码如下:

btnSend.setOnClickListener(new View.OnClickListener() {
	public void onClick(View v) {
		String phoneNo = edtPhoneNo.getText().toString();
		String message = edtContent.getText().toString();
		if (phoneNo.length() > 0 && message.length() > 0){
			//call sendSMS to send message to phoneNo
			sendSMS(phoneNo, message);
		}
		else
			Toast.makeText(getBaseContext(),
				"Please enter both phone number and message.",
				Toast.LENGTH_SHORT).show();
	}
});

发送短信的功能的代码如下:

private void sendSMS(String phoneNumber, String message) {
	// ---sends an SMS message to another device---
	SmsManager sms = SmsManager.getDefault();
	PendingIntent pi = PendingIntent.getActivity(this, 0, 
               new Intent(this,TextMessage.class), 0);
	//if message's length more than 70 ,
	//then call divideMessage to dive message into several part 
        //and call sendTextMessage()
	//else direct call sendTextMessage()
	if (message.length() > 70) {
		ArrayList<String> msgs = sms.divideMessage(message);
		for (String msg : msgs) {
			sms.sendTextMessage(phoneNumber, null, msg, pi, null);
		}
	} else {
		sms.sendTextMessage(phoneNumber, null, message, pi, null);
	}
	Toast.makeText(TextMessage.this, "短信发送完成", Toast.LENGTH_LONG).show();
}

如果你已经看了第2节介绍的SmsManager类的介绍,代码应该很好理解。在这里要说明的是,sendTextMessage方法中的第4个和第5个参数PendingIntent设为null,这样的话不能根据短信发出之后的状态做相应的事情,如短信发送失败后的提醒、接收者成功接收后的回执……完整的流程源码如下:

TextMessage.java源文件全部代码

3)运行前,还要在清单文件AndroidManifest.xml中加入允许发送短信的权限:

AndroidManifest.xml

3.1、运行SMS程序给另一个android模拟器发短信

运行上面我们编写的TextMessage程序,另外在Windows的命令行下切换到tools目录下,并输入emulator –data smsReceiver,我的如下:

image

这样就会启动一个android模拟器,如下所示:(注意它的编号:5556,就是用这个编号与它通信的

image

图2、通过emulator启动一个android模拟器

通过我们TextMessage程序启动的android模拟器,编写短信:

image

图3、TextMessage程序个5556模拟器发短信

点击发送之后,通过命令行启动的5556号android模拟器会收到我们刚才发送的短信,如下所示:

image

图4、收到短信的提示

tips:

如果通过命令行的emulator启动android模拟器提示“NO DNS servers found!”,这时我们发的短信模拟器是收不到的。

  • 在Windows下,如果电脑没有介入网络,即找不DNS服务器的话会出现这种情况!
  • 在Mac下,如果提示这个警告的话,可以这样解决:检查你是否有 /etc/resolv.conf文件,如果没有的话,通过下面的命令行
    ln -s /private/var/run/resolv.conf /etc/resolv.conf可以解决。

4、SMS增强(一)

上面我们实现了一个简单的SMS程序,下面我们要对它进行增强!你肯定已经注意到了,我们上面的SMS程序的sendTextMessage方法中的第4个和第5个参数PendingIntent设为null,即sentIntent和deliveryIntent。

第4个参数-sendIntent,当消息成功发送或发送失败都将被触发。广播接收者的结果码,Activity.RESULT_OK表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU之一表示错误。对应RESULT_ERROR_GENERIC_FAILURE,sentIntent可能包括额外的“错误代码”包含一个无线电广播技术特定的值,通常只在修复故障时有用。第5个参数-deliveryIntent,仅当目标接收到你的SMS消息才触发。

为了跟踪发出的短信的状态,实现和注册Broadcast Receiver(广播接收者)监听传递给sendTextMessage方法的参数Pending Intents。下面我们就实现和注册这个广播接收者:

String SENT_SMS_ACTION="SENT_SMS_ACTION";
String DELIVERED_SMS_ACTION="DELIVERED_SMS_ACTION";

//create the sentIntent parameter
Intent sentIntent=new Intent(SENT_SMS_ACTION);
PendingIntent sentPI=PendingIntent.getBroadcast(
		this,
		0, 
		sentIntent, 
		0);

//create the deilverIntent parameter
Intent deliverIntent=new Intent(DELIVERED_SMS_ACTION);
PendingIntent deliverPI=PendingIntent.getBroadcast(
		this,
		0, 
		deliverIntent, 
		0);

//register the Broadcast Receivers
registerReceiver(new BroadcastReceiver(){
	@Override
	public void onReceive(Context _context,Intent _intent)
	{
		switch(getResultCode()){
			case Activity.RESULT_OK:
				Toast.makeText(getBaseContext(), 
						"SMS sent success actions",
                        Toast.LENGTH_SHORT).show();
				break;
			case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
				Toast.makeText(getBaseContext(), 
						"SMS generic failure actions",
                        Toast.LENGTH_SHORT).show();
				break;
			case SmsManager.RESULT_ERROR_RADIO_OFF:
				Toast.makeText(getBaseContext(),
						"SMS radio off failure actions",
                        Toast.LENGTH_SHORT).show();
				break;
			case SmsManager.RESULT_ERROR_NULL_PDU:
				Toast.makeText(getBaseContext(), 
						"SMS null PDU failure actions",
                        Toast.LENGTH_SHORT).show();
				break;
		}
	}
},
new IntentFilter(SENT_SMS_ACTION));
registerReceiver(new BroadcastReceiver(){
	@Override
	public void onReceive(Context _context,Intent _intent)
	{
		Toast.makeText(getBaseContext(), 
				"SMS delivered actions",
                Toast.LENGTH_SHORT).show();				
	}
},
new IntentFilter(DELIVERED_SMS_ACTION));

在基本完成了要做的工作,接下来要做的就是将sendTextMessage的第4个和第5个参数改为sentPI、deliverPI,这样工作基本完成,修改后的sendSMS方法如下:

修改后的sendSMS方法完整代码

运行之后的,发送短信成功的话就可以看到如下界面:

sms

图5、增强SMS(一)

5、SMS增强(二)

下面这个增强是使SMS能够发送二进制数据。要发送数据要使用SmsManager类的sendDataMessage方法,跟sendTextMessage方法类似,只不过该方法多了一个目标端口的参数,构建该SMS的过程跟前面的类似这里就不在累述。

本系列的其它文章:


相关文章
|
15天前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
40 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
12天前
|
缓存 Java 测试技术
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
129 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
|
27天前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
164 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
25天前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
48 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
2月前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
97 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
11天前
|
安全 Android开发 iOS开发
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。
|
10月前
|
存储 Java 开发工具
Android开发的技术与开发流程
Android开发的技术与开发流程
437 1
|
7月前
|
安全 Android开发 Swift
安卓与iOS开发:平台差异与技术选择
【8月更文挑战第26天】 在移动应用开发的广阔天地中,安卓和iOS两大平台各占一方。本文旨在探索这两个系统在开发过程中的不同之处,并分析开发者如何根据项目需求选择合适的技术栈。通过深入浅出的对比,我们将揭示各自平台的优势与挑战,帮助开发者做出更明智的决策。
109 5
|
7月前
|
移动开发 搜索推荐 Android开发
安卓与iOS开发:一场跨平台的技术角逐
在移动开发的广阔舞台上,两大主角——安卓和iOS,持续上演着激烈的技术角逐。本文将深入浅出地探讨这两个平台的开发环境、工具和未来趋势,旨在为开发者揭示跨平台开发的秘密,同时激发读者对技术进步的思考和对未来的期待。
|
7月前
|
移动开发 开发工具 Android开发
探索安卓与iOS开发的差异:技术选择的影响
【8月更文挑战第17天】 在移动应用开发的广阔天地中,安卓和iOS两大平台各领风骚。本文通过比较这两个平台的编程语言、开发工具及市场策略,揭示了技术选择对开发者和产品成功的重要性。我们将从开发者的视角出发,深入探讨不同平台的技术特性及其对项目实施的具体影响,旨在为即将步入移动开发领域的新手提供一个清晰的指南,同时给予资深开发者新的思考角度。
82 3

热门文章

最新文章

  • 1
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    Android历史版本与APK文件结构
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 4
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 10
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥