zoukankan      html  css  js  c++  java
  • Android-监听操作系统短信

    想要访问Android操作系统的ContentProvider就需要明白以下原理:

    在Android操作系统里面的 /packsges/目录:

      apps: 很多的系统应用,例如:联系人,浏览器,音乐播放器,设置,相机 ......

                                          ............

      providers:系统对外暴露的ContentProvider:

                          

      这样就明白了,Android操作系统里面的应用(apps),是访问系统对外暴露的ContentProvider(providers)

    既然说Android操作系统里面的应用(apps),是访问系统对外暴露的ContentProvider(providers):

      /data/data/com.android.mms(放置在apps目录里面)

      /data/data/com.android.providers.telephony(放置在providers目录里面)

    mms(短信应用) 是调用 providers.telephony(内容提供者里面的数据),如图:


    短信应用没有数据库,那短信应用的数据是从哪里来的 ?

     

    答:短信应用是去 增删改查了 com.android.providers.telephony 暴露短信数据的应用

    apps:packages/apps/Mms   Android文件系统里 /data/data/com.android.mms    短信应用

    provider: packages/provider/  Android文件系统里 /data/data/com.android.providers.telephony 暴露短信数据的应用


    阅读packages/provider/TelephonyProvider/com.android.providers.telephony 暴露短信数据的应用 数据库:

    mmssms.db 数据库 其他应用是没有权限访问的,为什么所有应用都能获取到 packgeas/providers/....里面到所有应用,因为这些应用通过ContentProvider对外暴露了 

    阅读mmssms.db

    打开后:表非常多,等等, 但是只需要关注一张核心的表,sms

    关注的字段:address:短信号码,   date:短信时间    ,body:短信内容

                

    手机里只有一条短信:

     

    阅读packages/provider/TelephonyProvider/com.android.providers.telephony AndroidManifest.xml

     查看AndroidManifest.xml provider节点:关注ContentProvider对象,授权,权限 等;

    SmsProvider:内容提供者

    sms:授权,这授权真短

    exported:对外输出

    READ_SMS/WRITE_SMS:访问者必须要配置的权限

         <!-- This is a singleton provider that is used by all users.
                 A new instance is not created for each user. And the db is shared
                 as well. -->
            <provider android:name="SmsProvider"
                      android:authorities="sms"
                      android:multiprocess="false"
                      android:exported="true"
                      android:singleUser="true"
                      android:readPermission="android.permission.READ_SMS"
                      android:writePermission="android.permission.WRITE_SMS" />

    阅读packages/provider/TelephonyProvider/com.android.providers.telephony SmsProvider.java

     首先要找到的就是Uri,所以搜索UriMatcher的matcher.addURI

    private static final UriMatcher sURLMatcher =
                new UriMatcher(UriMatcher.NO_MATCH);
    
        static {
            sURLMatcher.addURI("sms", null, SMS_ALL);
            sURLMatcher.addURI("sms", "#", SMS_ALL_ID);
            sURLMatcher.addURI("sms", "inbox", SMS_INBOX);
            sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);
            sURLMatcher.addURI("sms", "sent", SMS_SENT);
            sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);
            sURLMatcher.addURI("sms", "draft", SMS_DRAFT);
            sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID);
            sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX);
            sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID);
            sURLMatcher.addURI("sms", "undelivered", SMS_UNDELIVERED);
            sURLMatcher.addURI("sms", "failed", SMS_FAILED);
            sURLMatcher.addURI("sms", "failed/#", SMS_FAILED_ID);
            sURLMatcher.addURI("sms", "queued", SMS_QUEUED);
            sURLMatcher.addURI("sms", "conversations", SMS_CONVERSATIONS);
            sURLMatcher.addURI("sms", "conversations/*", SMS_CONVERSATIONS_ID);
            sURLMatcher.addURI("sms", "raw", SMS_RAW_MESSAGE);
            sURLMatcher.addURI("sms", "attachments", SMS_ATTACHMENT);
            sURLMatcher.addURI("sms", "attachments/#", SMS_ATTACHMENT_ID);
            sURLMatcher.addURI("sms", "threadID", SMS_NEW_THREAD_ID);
            sURLMatcher.addURI("sms", "threadID/*", SMS_QUERY_THREAD_ID);
            sURLMatcher.addURI("sms", "status/#", SMS_STATUS_ID);
            sURLMatcher.addURI("sms", "sr_pending", SMS_STATUS_PENDING);
            sURLMatcher.addURI("sms", "icc", SMS_ALL_ICC);
            sURLMatcher.addURI("sms", "icc/#", SMS_ICC);
            //we keep these for not breaking old applications
            sURLMatcher.addURI("sms", "sim", SMS_ALL_ICC);
            sURLMatcher.addURI("sms", "sim/#", SMS_ICC);
     

     sURLMatcher.addURI("sms", null, SMS_ALL);  就是全部短信内容的Uir,path等于null,这样写是可以的,代表全部的意思

    在这源码中,一定有发送改变通知的代码:

    搜索:.notifyChange

    系统源码中 而且还另外两条通知的uri


    测试的应用:AndroidManifest.xml 配置权限

      <!--
            访问操作系统短信内容提供者应用,需要加入的权限
            android:readPermission="android.permission.READ_SMS"
            android:writePermission="android.permission.WRITE_SMS"
        -->
        <uses-permission android:name="android.permission.READ_SMS" />
        <uses-permission android:name="android.permission.WRITE_SMS"/>

    测试的应用:监听Android操作系统联系人内容提供者应用里面的短信数据发送的改变

    package liudeli.cp.client;
    
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.database.ContentObserver;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Handler;
    
    public class SmsActivity extends Activity {
    
        /**
         * 定义访问操作系统短信内容提供者应用的Uri
         * android:authorities="sms"
         */
        private final String AUTHORITIES = "content://sms";
        private Uri telephonyUri = Uri.parse(AUTHORITIES);
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_sms);
    
            /**
             * 注册内容观察者监听器:用于监听/data/data/com.android.providers.telephony内容提供者应用
             * 参数一:定义访问操作系统短信内容提供者应用的Uri android:authorities="sms"
             * 参数二:要联级
             * 参数三:监听器
             */
            getContentResolver().registerContentObserver(telephonyUri, true, contentObserver);
        }
    
        private ContentObserver contentObserver = new ContentObserver(new Handler()) {
    
            @Override
            public void onChange(boolean selfChange) {
                super.onChange(selfChange);
    
                // 短信数据发送改变啦 ...
    
                /**
                 * 查询短信最新的一条信息显示
                 */
                Cursor cursor = getContentResolver().query(telephonyUri,
                        new String[]{"address", "date", "body"},
                        null, // 查询条件为null
                        null , // 查询条件的值为null
                        " _id desc"); // 倒序,查询出来的第一条就是最新的短信
    
                // Cursor游标必须往下移,才能取出数据
                if (cursor.moveToFirst()) { // 移动到第一条
                    String address = cursor.getString(cursor.getColumnIndex("address"));
                    String body = cursor.getString(cursor.getColumnIndex("body"));
                    alterUser(address, body);
                }
    
                // 关闭游标
                cursor.close();
            }
        };
    
        private void alterUser(String address, String body) {
            new AlertDialog.Builder(this)
                    .setPositiveButton("我知道了", null)
                    .setTitle("注意")
                    .setMessage("短信发送改变啦, /n 短信号码:" + address + " /n 短信内容:" + body)
                    .show();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            /**
             * 解除监听器
             */
            getContentResolver().unregisterContentObserver(contentObserver);
        }
    }

    Android操作系统里面的应用(apps),是访问系统对外暴露的ContentProvider(providers)

    自己开发的应用,也是可以访问系统对外暴露的ContentProvider(providers)

  • 相关阅读:
    简单的测试用例计划放法
    黑盒测试用例设计方法-等价类划分
    Redis净化板
    爬虫部署与Django
    怎样实现前端的优化
    关于Apache简介笔记
    yield生成器的经典案例
    石头剪刀布
    函数内是否可以修改传递进来的列表
    不定长参数的传递
  • 原文地址:https://www.cnblogs.com/android-deli/p/10130437.html
Copyright © 2011-2022 走看看