刚学到康师傅内容提供者,我想对短信进行备份与恢复,无奈又没有WRITE_SMS的权限,那么要写入短信怎么办,通过我一顿百度+谷歌搜索操作,需要把app整成默认短信应用,才能对短信进行插入和删除。
下面记录下如何插入短信
- 测试机型:一加3 ROM:魔趣7.1.2
sms表中重要字段 此表路径:data/data/user_de/0/com.android.providers.telephony/mmssms.db
字段 | 说明 |
---|---|
address | 手机号码 |
person(不管) | 联系人列表里的序号,陌生人为null |
date | 收件箱:收到短信的时间;发件箱:短信发送的时间 |
date_sent | 只针对收件箱;为对方什么时候开始发送短信的时间 |
protocol | SMS协议如果是收到的为0 发出去的为null |
read | 读与否;1为已读 0为未读 |
type | 短信类型;1为收到的信息 2为发送出去的 |
reply_path_present | 回复路径;发送出去的应该为null;收到的为0 |
body | 短信内容 |
service_center(不管) | 服务中心号码 |
locked(不管) | 是否锁定 这个不管;统统填0就对了 |
sub_id | SIM卡 如果是卡一对应的就是1,否则就是卡二2;;就是手机卡的ICCID |
error_code(不管) | 错误代码:统统填0就对了 |
creator | 发送或接收此信息的APP包名 |
seen | 看得见看不见;;;不知道啥意思,应该指的是 是否隐藏 统统填1就对了 |
设为短信默认应用四个必备条件
- 在在Manifest文件中:manifest-->application-->activity里加入Intent内容
<!-- 具备短信默认应用条件 1 -->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
- 在Manifest文件中:manifest-->application下申明 SmsReceiver和MmsReceiver就是广播接收者,继承BroadcastReceiver并实现其onReceive方法就可以了,不需要做任何操作。 HeadlessSmsSendService继承自Service 并实现其onBind方法即可不需要做任何操作。
<!-- 具备短信默认应用条件 2-->
<!-- BroadcastReceiver that listens for incoming SMS messages -->
<receiver
android:name=".SmsReceiver"
android:permission="android.permission.BROADCAST_SMS"
tools:ignore="WrongManifestParent">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver>
<!-- 具备短信默认应用条件 3 -->
<!-- BroadcastReceiver that listens for incoming MMS messages -->
<receiver
android:name="com.aizi.smsdemo.MmsReceiver"
android:permission="android.permission.BROADCAST_WAP_PUSH"
tools:ignore="WrongManifestParent">
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
<!-- 具备短信默认应用条件 4 -->
<!-- Service that delivers messages from the phone "quick response" -->
<service
android:name="com.aizi.smsdemo.HeadlessSmsSendService"
android:exported="true"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
tools:ignore="WrongManifestParent">
<intent-filter>
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</service>
插入一条短信试试
public class SMSBean {
//表中ID
private String _id;
//电话号码
private String address;
//收到短信时间
private long date;
//发送短信者 发送时间
private long date_sent;
//SMS协议如果是收到的为0 发出去的为null
private String protocol;
//读与否;1为已读 0为未读
private String read;
//短信类型;1为收到的信息 2为发送出去的
private String type;
//回复路径;发送出去的应该为null;收到的为0
private String reply_path_present;
//短信内容
private String body;
//SIM卡 如果是卡一对应的就是1,否则就是卡二2
private String sub_id;
//发送或接收此信息的APP包名
private String creator;
//看;;;什么鬼玩意不管了,统统填1就对了
private String seen;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
public long getDate_sent() {
return date_sent;
}
public void setDate_sent(long date_sent) {
this.date_sent = date_sent;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String getRead() {
return read;
}
public void setRead(String read) {
this.read = read;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getReply_path_present() {
return reply_path_present;
}
public void setReply_path_present(String reply_path_present) {
this.reply_path_present = reply_path_present;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getSub_id() {
return sub_id;
}
public void setSub_id(String sub_id) {
this.sub_id = sub_id;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getSeen() {
return seen;
}
public void setSeen(String seen) {
this.seen = seen;
}
}
- 这边,先把所有短信全删除了再插入
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
defaultSMSApp();
}
//检查是否是默认短信应用
private void defaultSMSApp() {
//获取手机当前设置的默认短信应用包名
String defaultSmsPackage = Telephony.Sms.getDefaultSmsPackage(this);
//获取当前应用包名
String packageName = getPackageName();
Log.d(TAG, "当前默认短信应用包名====" + defaultSmsPackage);
Log.d(TAG, "当前应用包名====" + packageName);
//如果当前的默认短信应用不是本APP就将本App设置为默认短信应用
if (defaultSmsPackage != packageName) {
Intent smsIntent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
smsIntent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, packageName);
startActivity(smsIntent);
}
}
/**
* 往收件箱插入一条未读的信息
* @param view
*/
public void setMessage(View view) {
/** 定义所有信息写入地址 **/
Uri uri = Uri.parse("content://sms");
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put("address", "10086");//手机号码
values.put("date", "1584711942635");//收到短信的时间
values.put("date_sent", "1584711936000");//对方发送的时间
//values.put("protocol",0);//SMS协议如果是收到的为0 发出去的为null
values.put("read", 0);//读与否;1为已读 0为未读
values.put("type", 1);//短信类型;1为收到的信息 2为发送出去的
values.put("reply_path_present", 0);//回复路径;发送出去的应该为null;收到的为0
values.put("body", "【湖南政务外网平台】湖南省就业服务中心温馨提醒:湖南省工业设备安装有限(国企)助力就业扶贫,现招聘工业设备安装工人一批,招聘对象为湖南省建档立卡贫困劳动力,年龄18-55岁,身体健康。主要工种为水电安装工、电工、焊工、机械设备安装工等。工作地点为全国各地设备安装项目所在地,月综合收入3000-6000元。联系人:刘卫超,联系电话:0731-28269436、18890333372。【省人社厅】");//短信内容
values.put("sub_id", "1");//SIM卡 如果是卡一对应的就是1,否则就是卡二2;;就是手机卡的ICCID
values.put("seen", 1);//看or看不见;;;者应该指的是 是否隐藏 统统填1就对了
// values.put("creator","com.android.messaging");//插入包名整不动啊。就算改成其它的短信应用的包名,数据里还是本应用的包名
Uri uri1 = cr.insert(uri, values);
Log.d(TAG, "插入短信成功Uri ===" + uri1);
}
public void getMessage(View view) {
//遍历查询到的所有短信内容的集合,并输出
ArrayList<SMSBean> beanArrayList = querySMS();
Log.d(TAG, "====================================================");
for (int i = 0; i < beanArrayList.size(); i++) {
SMSBean smsBeans = beanArrayList.get(i);
String id = smsBeans.get_id(); //id
String address = smsBeans.getAddress();//号码
String protocol = smsBeans.getProtocol();//SMS协议如果是收到的为0 发出去的为null
String read = smsBeans.getRead();//读与否
String type = smsBeans.getType();//短信类型1为收到的信息 2为发送出去的
String reply_path_present = smsBeans.getReply_path_present();//回复路径;发送出去的应该为null;收到的为0
String body = smsBeans.getBody();//短信内容
String sub_id = smsBeans.getSub_id();//手机卡ID_卡一还是卡二
String seen = smsBeans.getSeen();//是否可见1为可见
long date_sent = smsBeans.getDate_sent();//发信方发送时间
long date = smsBeans.getDate();//短信收到时间,或者发送短信的发送时间
String creator = smsBeans.getCreator();//操作本短信的应用包名
//将时间转换成正常格式
String dateSent = timeConversion(date_sent);
String dateReceive = timeConversion(date);
switch (read) {
case "1":
read = "已读";
break;
case "0":
read = "未读";
break;
}
switch (type) {
case "1":
type = "收到的信息";
break;
case "2":
type = "发出的信息";
break;
}
if (sub_id.equals("1")) {
sub_id = "中国电信";
} else if (sub_id.equals("2")) {
sub_id = "俄罗斯电信";
} else {
sub_id = "非本手机上的手机卡发出或收到的信息";
}
switch (seen) {
case "1":
seen = "可见";
break;
case "0":
seen = "不可见";
break;
}
Log.d(TAG, "id--->" + id);
Log.d(TAG, "address号码--->" + address);
Log.d(TAG, "protocol SMS协议--->" + protocol);
Log.d(TAG, "read 是否已读--->" + read);
Log.d(TAG, "type 短信类型--->" + type);
Log.d(TAG, "reply_path_present 回复路径--->" + reply_path_present);
Log.d(TAG, "body 短信内容--->" + body);
Log.d(TAG, "sub_id 卡一还是卡二--->" + sub_id);
Log.d(TAG, "seen 信息是否可见--->" + seen);
Log.d(TAG, "date_sent 发信人的发信时间--->" + dateSent);
Log.d(TAG, "date 收件时间--->" + dateReceive);
Log.d(TAG, "creator 短信App--->" + creator);
Log.d(TAG, "====================================================");
}
}
private ArrayList<SMSBean> querySMS() {
//查询所有短信内容,并把集合返回给调用者
Uri uri = Uri.parse("content://sms");
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(uri, new String[]{"_id", "address", "date", "date_sent", "protocol", "read", "type", "reply_path_present", "body", "sub_id", "seen", "creator"}, null, null, null);
ArrayList<SMSBean> beanArrayList = new ArrayList<>();
while (cursor.moveToNext()) {
SMSBean smsBean = new SMSBean();
smsBean.set_id(cursor.getString(cursor.getColumnIndex("_id")));
smsBean.setAddress(cursor.getString(cursor.getColumnIndex("address")));
smsBean.setProtocol(cursor.getString(cursor.getColumnIndex("protocol")));
smsBean.setRead(cursor.getString(cursor.getColumnIndex("read")));
smsBean.setType(cursor.getString(cursor.getColumnIndex("type")));
smsBean.setReply_path_present(cursor.getString(cursor.getColumnIndex("reply_path_present")));
smsBean.setBody(cursor.getString(cursor.getColumnIndex("body")));
smsBean.setSub_id(cursor.getString(cursor.getColumnIndex("sub_id")));
smsBean.setSeen(cursor.getString(cursor.getColumnIndex("seen")));
smsBean.setDate(cursor.getLong(cursor.getColumnIndex("date")));
smsBean.setDate_sent(cursor.getLong(cursor.getColumnIndex("date_sent")));
smsBean.setCreator(cursor.getString(cursor.getColumnIndex("creator")));
beanArrayList.add(smsBean);//将对象添加到集合
}
return beanArrayList;
}
public void deleteMessage(View view) {
//删除所有短信内容
ArrayList<SMSBean> beanArrayList = querySMS();
Uri uri = Uri.parse("content://sms");
ContentResolver cr = getContentResolver();
for (int i = 0; i<beanArrayList.size();i++) {
SMSBean smsBean = beanArrayList.get(i);
String id = smsBean.get_id();
int delete = cr.delete(uri, "_id=?", new String[]{id});
Log.d(TAG,"成功删除"+(i+1)+"条通短信记录");
}
}
/**
* 时间戳转换成正常时间yyyy-MM-dd HH:mm:ss
*
* @param longTime 要转换的时间戳
* @return 返回正常的时间格式
*/
@SuppressLint("SimpleDateFormat")
private String timeConversion(Long longTime) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(longTime);
String time = simpleDateFormat.format(date);
//Log.d(TAG,time+'\t'+"Long时间戳转换成正常格式日期");
return time;
}
}
一加3手机:魔趣7.1.2版本-----测试没问题
zuk手机:lineageos_7.1.2版本-----测试没问题
三星S9+:9.0版本-----测试没啥大问题 - 恢复短信的时候,三星是通过imei_id(IMEI)判断短信是卡1的短信还是卡2的短信的。不像上面那两手机是通过sub_id(icc_id(ICCID))来判断的。 - sub_id来自:data/data/user_de/0/com.android.providers.telephony/databases/telephony.db/siminfo表/_id字段
小米5:MIUI_10.2_安卓8.0版本----测试不行。