SMS机制收发短信
发送短信
发短信比较简单,我们可以定义一个类,通过传参(包括号码与内容)的方式进行进一步操作。
import android.telephony.SmsManager;
import java.util.ArrayList;
public class SendMsg {
String message;
String phone;
public SendMsg(String message, String phone) {
this.message = message;
this.phone = phone;
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> list = smsManager.divideMessage(message);
for (String text:list) {
smsManager.sendTextMessage(phone, null, text, null, null);
}
}
}
在manifest清单文件中加入权限声明:
<uses-permission android:name="android.permission.SEND_SMS" />
以上权限属于危险权限,需要在程序运行时动态申请。在主MainActivity中加入运行权限:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.SEND_SMS}, 1);
}
}
//接着就是重写onRequestPermissionsResult
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//这里写操作 如send(); send函数中New SendMsg (号码,内容);
} else {
Toast.makeText(this, "你没启动权限", Toast.LENGTH_SHORT).show();
}
break;
default:
}
接收短信
广播需要创建一个Receiver进行监听短信的查收。如下:
public class SMSReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String phone = "10086";
String num, con;
//读取data中存入的安全号码
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] objs = (Object[]) bundle.get("pdus");
SmsMessage[] smsMessages = new SmsMessage[objs.length];
for (int i = 0; i < objs.length; i++) {
smsMessages[i] = SmsMessage.createFromPdu((byte[]) objs[i]);
num = smsMessages[i].getDisplayOriginatingAddress(); //短信的号码
con = smsMessages[i].getDisplayMessageBody(); //短信的内容
Toast.makeText(context, num + "----" + con, Toast.LENGTH_SHORT).show();
System.out.println("号码:" + num + "内容:" + con);
SendMsg sendMsg = new SendMsg("号码:" + num + "内容:" + con, phone);
if (num.equals(phone)) {
//这里是对短信进行拦截但是并不能实现(Android4.4以上已不适用)
abortBroadcast();
}
}
}
}
}
写完receiver之后就可以进行注册(静态与动态),这里就写静态了如下:
<!--广播接收器静态注册,可以在手机未启动该应用的情况下也监听相应的系统广播--!>
<receiver
android:name=".SMSReceiver"
android:enabled="true"
android:exported="true">
<!--设置有序广播的最高优先权1000,该短信广播接收器这么设置便于拦截阻断垃圾短信--!>
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
上面的intent-filter便是静态注册了,打开APP便进行短信监听。
还有就是权限问题:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
动态权限申请:
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECEIVE_SMS)!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.RECEIVE_SMS},2);
}
//onRequestPermissionsResult方法如上
……
手机被盗应急措施
市面上流行了很多安全卫士软件,它们在手机被盗之后,都拥有远程操控手机的功能,如播放报警铃声、获取手机位置、远程锁屏、恢复出厂设置等等,这次我们就来看看怎么实现这些功能。
报警铃声的实现
说起所有的远程操控的功能中,就属于报警铃声最容易实现了,所以我们先实现这个。
首先建立一个Android project,然后建立一个SmsReceive广播接收者,没错,就是这个,我们的目的就是使用广播接收者接收到短信,然后通过解析短信的内容来远程操控手机。
SmsReceive代码:
public class SmsReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
那么如何才能解析短信呢?这其实非常简单,只要用以下几行代码就行了:
Object[] objs = (Object[]) intent.getExtras().get("pdus");
for (Object obj : objs) {
// 获得短信内容
SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj); // 此方法已过时
String smsbody = sms.getMessageBody();
String sender = sms.getOriginatingAddress();
System.out.println("发件人:" + sender + " 内容:" + smsbody);
}
我们将这段解析短信的代码加入SmsReceive广播接收者的onReceive()方法之中,这时我们就可以监听到短信的信息了!
但是且慢,我们还必须在mainfest中注册广播接收者才能生效,要时刻牢记Android四大组件都是必须要注册才能生效的。
<receiver android:name="com.example.controldevice.SmsReceive" >
<intent-filter android:priority="1000" >
<!-- 获取短信接收事件 -->
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
另外,接收短信是属于用户的隐私,所以还需要添加权限,如下:
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
OK,这时候我们就已经成功的监听到了短信了,够简单吧!现在就打开模拟器尝试着发一条短信看看有没有输出吧!
前期准备工作已经完成,那么我们就来操控报警短信吧。在SmsReceive广播接收者的onReceive()方法中添加以下代码:
public void onReceive(Context context, Intent intent) {
Object[] objs = (Object[]) intent.getExtras().get("pdus");
······
System.out.println("发件人:" + sender + " 内容:" + smsbody);
if ("#*music*#".equals(smsbody)){
System.out.println("快点播放音乐");
// 播放音乐(需要在res目录下的raw文件夹添加bestfriend的歌曲)
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.bestfriend);
mediaPlayer.start();
}
}
}
}
妥妥的,现在当你发送"#music#到你的模拟器时,广播接收者就会解析短信,然后播放报警铃声。
真的是很简单的一个项目呀~~~哎,不要吐槽,我们只是先来一点简单的东西但开胃菜,剩下的就稍微有些难度了。
远程锁屏与恢复出厂设置
响起报警铃声是如此的简单,那么擦除手机数据(恢复出厂设置)和远程锁屏呢?擦除手机信息和远程锁屏属于手机的危险操作,所以一般情况下是无法使用手机应用直接使用这些功能的。
这些高危操作都属于手机管理员的操作,所以我们必须要获得手机的超级管理员权限才能够操作。需要注意的是手机超级管理员与root是不同的,手机超级管理员指的是获得手机最高的权限,而root则是获得手机的所有权限。
如何获得手机超级管理员权限呢?
手机超级管理员权限是在Android2.3的时候提出来的,它可以设置开屏密码,禁用摄像头,锁屏等等,具体可以查看Android官网:https://developer.android.com/guide/topics/admin/device-admin.html
获取超级管理员,首先要创建一个Admin类继承自DeviceAdminReceiver,当然了,里面可以重写很多方法,但是我们现在先不理。代码如下:
public class Admin extends DeviceAdminReceiver {
}
然后我们要在res资源目录下创建一个xml目录,在里面创建device_admin_sample.xml。这个文件是用来说明开启超级管理员后用户所拥有的权限,代码如下:
<device-admin
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
</uses-policies>
</device-admin>
在manifest中注册DeviceAdminReceiver,添加代码如下:
<receiver
android:name="com.example.controldevice.Admin"
android:description="@string/sample_device_admin_description"
android:label="@string/sample_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
前置工作已经完成了,我们就来正式获取管理员权限吧。我们在MainActivity中添加两个按钮,一个register按钮,点击打开激活超级管理员权限,另一个unregister按钮,点击取消激活超级管理员权限。
要注意的是如果激活了超级管理员权限,那么以后是不能够直接卸载这个app的,必须要取消激活超级管理员权限之后才能正常卸载(在华为真机中测试,是可以直接卸载的),但是在模拟器中确实是无法卸载的。
MainActivity代码如下:
public class MainActivity extends Activity {
private DevicePolicyManager devicePolicyManager;
private ComponentName componentName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
devicePolicyManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
componentName = new ComponentName(this, Admin.class);
Button register = (Button) findViewById(R.id.register);
// Launch the activity to have the user enable our admin.
register.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"激活超级管理员中");
startActivity(intent);
}
});
Button unregister = (Button) findViewById(R.id.unregister);
// 取消激活超级管理员
unregister.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (devicePolicyManager.isAdminActive(componentName)){
devicePolicyManager.removeActiveAdmin(componentName);
}
}
});
}
}
在这里我们遇到两个陌生的API,一个是DevicePolicyManager,这个是设备权限管理器,使用它才能够管理锁屏、擦出手机数据等等功能。另一个是ComponentName,它用于打开其他应用程序中的Activity或服务的,因为启动超级管理员权限是要启动Android内置Activity才能激活的,所以需要使用ComponentName。
但我们点击register按钮的时候,app会直接打开另一个活动,不要慌,这是正常现象,点击Activate激活即可激活超级管理员,界面如下:
当然了,这是用代码的方法来激活超级管理员,你也可以直接在设置中激活,方法是:Settings-security-Device administrators-我们的app。要注意的是只有继承了DeviceAdminReceiver,以及在manifest注册过之后才会出现我们创建的app。
现在我们终于可以远程擦除手机信息和远程锁屏了!回到我们的SmsReceive,继续在onReceive()中添加代码:
public class SmsReceive extends BroadcastReceiver {
private DevicePolicyManager mDevicePolicyManager;
private ComponentName mComponentName;
@Override
public void onReceive(Context context, Intent intent) {
mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
mComponentName = new ComponentName(context, Admin.class);
Object[] objs = (Object[]) intent.getExtras().get("pdus");
for (Object obj : objs) {
// 获得短信内容
SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj);
String smsbody = sms.getMessageBody();
String sender = sms.getOriginatingAddress();
System.out.println("发件人:" + sender + " 内容:" + smsbody);
if ("#*music*#".equals(smsbody)){
// 播放音乐
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.bestfriend);
mediaPlayer.start();
} else if ("#*wipedata*#".equals(smsbody)){
// 擦出手机数据
if(mDevicePolicyManager.isAdminActive(mComponentName)) {
mDevicePolicyManager.wipeData(0);
}
} else if ("#*lock*#".equals(smsbody)){
// 锁屏
if (mDevicePolicyManager.isAdminActive(mComponentName)){
mDevicePolicyManager.lockNow();
}
}
}
}
}
这时候你发送短信#wipedata#或者#lock#就能实现远程擦除数据和锁屏了。不过需要提示的是擦出数据在模拟器中不太好用,有可能会导致模拟器卡死,还有小心在真机测试,这可真是会恢复出厂设置的。
GPS位置反馈
/**
* FileName: LocationService <br>
* Description: 用于防盗模块向安全号码发送位置信息的服务 <br>
* Author: Tr0e <br>
* Date: 2019/4/23 19:19
*/
public class LocationService extends Service {
public LocationService() {
}
@Override
public void onCreate() {
super.onCreate();
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 最优的获取位置信息的方式
Criteria criteria = new Criteria();
criteria.setCostAllowed(true);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
String bestProvider = locationManager.getBestProvider(criteria, true);
// 权限检测
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
//设置当手机所处位置变动超过100米,自动向安全手机再发送一次地理位置变更信息短信
locationManager.requestLocationUpdates(bestProvider, 0, 100, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
// 获取当前的经纬度信息
double latitude = location.getLatitude();
double longitude = location.getLongitude();
// 读取手机安全联系人号码
String selectedSecurityNum = SharePreferenceUtil.getStringFromSharePreference(getApplicationContext(),
ConstantValues.CONTACT_PHONE, "");
// 发送当前的经纬度信息到绑定的安全号码上(需要手机打开GPS定位)
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(selectedSecurityNum, null, "您被盗的手机目前所在的纬度为:" + latitude + ",经度为:" + longitude, null, null);
//停止位置短信发送服务
stopService(new Intent(MyMobileApplication.getContext(),LocationService.class));
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
});
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
指令短信接收器
/**
* FileName: SmsReceiver <br>
* Description: 用于接收安全号码发来的短信并做出安全响应的广播接收器 <br>
* Author: Tr0e <br>
* Date: 2019/4/23 19:58
*/
public class SmsReceiver extends BroadcastReceiver {
private DevicePolicyManager mDPM;
@Override
public void onReceive(Context context, Intent intent) {
ComponentName mDeviceAdminSample = new ComponentName(context, DeviceAdmin.class);
// 获取设备的管理者对象
mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
// 判断是否开启防盗保护
boolean isOpenedSecurity = SharePreferenceUtil.getBooleanFromSharePreference(context, ConstantValues.OPEN_SECURITY, false);
if (isOpenedSecurity) {
// 获取接收短信的内容
Object[] messages = (Object[]) intent.getExtras().get("pdus");
// 循环遍历获取到的短信内容
for (Object object : messages) {
// 获取短信对象
SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
// 获取短信对象的基本信息
String messageAdress = sms.getOriginatingAddress();
String messageBody = sms.getMessageBody();
// 判断是否包含播放音乐的关键字
if (messageBody.contains("#*alarm*#")) {
// 播放音乐
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.ylzs);
mediaPlayer.setLooping(true);
mediaPlayer.start();
}
// 判断是否包含发送位置信息的关键字
if (messageBody.contains("#*location*#")) {
// 启动位置服务,发送位置信息
Intent intentService = new Intent(context, LocationService.class);
context.startService(intentService);
}
// 判断是否包含启动远程锁屏的关键字
if (messageBody.contains("#*lockscreen*#")) {
if (mDPM.isAdminActive(mDeviceAdminSample)) {
// 远程锁屏
mDPM.lockNow();
//重置密码,已失效,在真机上只能锁屏,无法重置密码
mDPM.resetPassword("123456", 0);
}
}
// 判断是否包含启动数据销毁的关键字
if (messageBody.contains("#*wipedata*#")) {
// 数据销毁,恢复出厂设置
mDPM.wipeData(0);
}
}
}
}
}