阳光沙滩
让学习编程变得简单
短信的恢复
发表于 2020-03-22    阅读次数 88

刚学到康师傅内容提供者,我想对短信进行备份与恢复,无奈又没有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只针对收件箱;为对方什么时候开始发送短信的时间
protocolSMS协议如果是收到的为0 发出去的为null
read读与否;1为已读 0为未读
type短信类型;1为收到的信息 2为发送出去的
reply_path_present回复路径;发送出去的应该为null;收到的为0
body短信内容
service_center(不管)服务中心号码
locked(不管)是否锁定 这个不管;统统填0就对了
sub_idSIM卡 如果是卡一对应的就是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下申明 SmsReceiverMmsReceiver就是广播接收者,继承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版本----测试不行。