精华内容
下载资源
问答
  • 这个可能在不同系统中都遇到了问题,并且和其他短信访问app,例如微信电话本发生冲突,下面内容主要针对Android4.4以下系统,和部分被修改的操作系统,例如小米 首先就说和微信电话本冲突情况,由于微信电话本...

    最近项目遇到短信拦截的问题,新短信到达以后,项目app希望可以提示用户未读短信的数据,并且可以将短信置为已读。

    这个可能在不同系统中都遇到了问题,并且和其他短信访问的app,例如微信电话本发生冲突,下面内容主要针对Android4.4以下系统,和部分被修改的操作系统,例如小米


    首先就说和微信电话本冲突的情况,由于微信电话本也要实现上述功能,可是它有一个坑就是,它收到短信以后,就将短信置为已读(完全搞不明白为什么要这样做啊喂!)

    由于它在系统中的优先级比较高,所以当我的App读取短信的时候,就没有未读短信了!


    下面就这个内容,来说一下短信接收优先级的问题。


    众所周知,监听短信有两种方式

    1,是注册一个BroastReceiver,监听系统的短信到底的广播

    public class SmsReceiver extends BroadcastReceiver{
    	
    	public SmsReceiver() {
    		Log.i("cky", "new SmsReceiver");
    	}
    	@Override
    	public void onReceive(Context context, Intent intent) {  
    		// TODO Auto-generated method stub
    		Log.i("cky", "接收到广播");		  		
    	}		
    }


    2,是使用ContentObserver来监听系统短信数据库的变化

    public class SmsObserver extends ContentObserver{    
        public SmsObserver(Context context, Handler handler) {
            super(handler);
            mContext = context;                 
        }
    
        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            Log.i("cky","短信数据库变化了");
        }   
    }

    那么问题来了,如果我两个方法都使用了,到底谁会先接收到短信到达的通知呢?


    经过测试,虽然没有真正去看源码,发现应该是这样的:

    1,当短信到底,首先BroastReceiver会接收到通知,此时该新短信,会被系统记录进系统的短信数据库

    如果我们在BroastReceiver里面查询短信数据库,有可能查询不到新短信,因为数据库写入需要一定时间

    经过测试,如果onReceive()方法里面,我暂停1秒以后再去查短信数据库,才能查到新短信的信息

    2,当系统数据库被写入后,马上会通知ContentObserver,调用其onChange()方法


    由于我的app是使用ContentObserver去探测短信的,所以当然要比微信电话本慢,测试结果是,

    在4.4系统以下,和4.4的小米系统,当我的onChange()方法去查询数据库的时候,果然查询到新短信记录,但是很快就被微信电话本清除了。。

    在google原生6.0系统,onChange()方法查询数据库时,没有查询到新短信,说明在这之前,记录就被微信电话本清除了。。。


    那么解决办法是什么呢?

    我们要想办法抢在微信电话本前面收到短信,然后把短信广播给拦截了(短信广播是有序广播,在4.4以下系统,是可以阻止其传播的)

    但是问题是我的app不是短信应用啊,我这样做的话,用户就收不到短信了,体验太差。

    而且问题来了,就是我怎么样才能抢在微信电话本前面呢,我们能做的事情,微信电话本都能做。

    所以结局悲剧了(>﹏<),这个bug没有办法修改!


    不过我还有要说一下短信拦截的机制,让我们的app第一个接收到短信到底的消息

    首先我们要注册BroastReceiver,根据源码,广播接收优先级有以下规律:



    静态广播接收器 由PackageManagerService负责,当手机启动时(或者新安装了应用),PackageManagerService负责扫描手机中所有已安装的APP应用(题外话,确定不再使用的APP需要卸载了),将AndroidManifest.xml中 有关注册广播的信息 解析出来,存储至一个全局静态变量当中mReceivers。
      需要注意的是:
     1 PackageManagerService扫描目录的顺序如下:
      system/framework
      system/app
      vendor/app
      data/app
      drm/app-private
      2 当处于同一目录下时:按照file.list()的返回顺序。(题外话:因为在data/app下的应用都是用户安装的,并且都是以com.xxx.xxx-1.apk 的形式出现,所以如果打算做手机管家之类的应用,需要好好的研究下包名,争取在file.list()的独木桥下抢的头筹---优先接收开机启动完成的广播。)
       3 在此处并未对 接收顺序做完整的排序。(注意修饰词完整的,毕竟先扫描的当然会有一定优先级)
     
        动态广播接收器 由ActivityManagerService负责,当APP的服务或者进程起来之后,执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个全局静态变量
    mReceiverResolver中。
        需要注意的是:
        1 这个并非是一成不变的,当程序被杀死之后,  已注册的动态广播接收器也会被移出mReceiverResolver,直到下次程序启动,再进行动态广播的注册,当然这里面的顺序也已经变更了一次。
        2  这里也并没完整的进行广播的排序,只记录的注册的先后顺序,并未有结合优先级的处理。
     
    当有广播发出时,接收顺序如下:


    在ActivityManagerService处理广播,当广播为有序广播时,将动态广播接收器和动态广播接收器合并起来,形成最终的有序广播接收顺序。
       上述的规则1排序为:
                                    1 优先级高的先接收
                                    2 同优先级的动静态广播接收器,动态优先于静态
                                    3 同优先级的动态广播接收器  或者同优先级的静态广播接收器,按照图1 的流程注册顺序。
                                       即静态:先扫描的大于后扫描的,动态:先注册的大于后注册的。

      
       当广播为普通广播时,规则2排序为:
                                    1 无视优先级,动态广播接收器优先于静态广播接收器
                                    2 同规则1排序的第3点

     
    接下来请看代码以片段:

    private final int broadcastIntentLocked(ProcessRecord callerApp,   
            String callerPackage, Intent intent, String resolvedType,   
            IIntentReceiver resultTo, int resultCode, String resultData,   
            Bundle map, String requiredPermission,   
            boolean ordered, boolean sticky, int callingPid, int callingUid) {   
    
        …………
        …………
        
        // 静态广播接收器list
        List receivers = null; 
        
        // 动态广播接收器List
        List<BroadcastFilter> registeredReceivers = null;   
    
        // 获取静态广播接收器mReceivers
        try {   
            if (intent.getComponent() != null) {   
                // Broadcast is going to one specific receiver class...   
                ActivityInfo ai = AppGlobals.getPackageManager().   
                    getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);   
                if (ai != null) {   
                    receivers = new ArrayList();   
                    ResolveInfo ri = new ResolveInfo();   
                    ri.activityInfo = ai;
                    receivers.add(ri);   
                }   
            } else {   
                // Need to resolve the intent to interested receivers...   
                if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)   
                         == 0) {   
                    receivers =   
                        AppGlobals.getPackageManager().queryIntentReceivers(   
                                intent, resolvedType, STOCK_PM_FLAGS);   
                } 
                // 获取动态广播接收器mReceiverResolver
                registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);   
            }   
        } catch (RemoteException ex) {   
            // pm is in same process, this will never happen.   
        }   
      
        final boolean replacePending =   
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;   
          
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;  
        ……
        // 如果接收到的广播 是普通广播。
        if (!ordered && NR > 0) {   
            // If we are not serializing this broadcast, then send the   
            // registered receivers separately so they don't wait for the   
            // components to be launched.   
            BroadcastRecord r = new BroadcastRecord(intent, callerApp,   
                    callerPackage, callingPid, callingUid, requiredPermission,   
                    registeredReceivers, resultTo, resultCode, resultData, map,   
                    ordered, sticky, false);   
    
        // 很明显接收到普通广播之后,在这只处理了动态广播 registeredReceivers,对于普通广播而言,动态广播接收器要优先于静态广播接收器 无关设置的优先级
            boolean replaced = false;   
            if (replacePending) {   
                for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {   
                    if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {   
                        if (DEBUG_BROADCAST) Slog.v(TAG,   
                                "***** DROPPING PARALLEL: " + intent);   
                        mParallelBroadcasts.set(i, r);   
                        replaced = true;   
                        break;   
                    }   
                }   
            }   
            if (!replaced) {   
                mParallelBroadcasts.add(r);   
                scheduleBroadcastsLocked();   
            }   
            //将registeredReceivers置为null,后面只处理静态广播接收器,所以不会有冲突。
            registeredReceivers = null;   
            NR = 0;   
        }   
        
        //如果是有序广播,将静态广播接收器和动态广播接收器组合成一个最终的顺序
        int ir = 0;   
        if (receivers != null) {   
            ...   
            //合并的过程,注意顺序   
            int NT = receivers != null ? receivers.size() : 0;   
            int it = 0;   
            ResolveInfo curt = null;   
            BroadcastFilter curr = null;   
            while (it < NT && ir < NR) {   
                if (curt == null) {   
                    curt = (ResolveInfo)receivers.get(it);   
                }   
                if (curr == null) {   
                    curr = registeredReceivers.get(ir);   
                }   
                //如果动态广播接收器优先级高于或者等于静态广播接收器,那么就插到前面      
                //很明显动态的要在静态的前面 
                if (curr.getPriority() >= curt.priority) {   
                    // Insert this broadcast record into the final list.   
                    receivers.add(it, curr);   
                    ir++;   
                    curr = null;   
                    it++;   
                    NT++;   
                } else {   
                    // Skip to the next ResolveInfo in the final list.   
                    it++;   
                    curt = null;   
                }   
            }   
        }


    OK,了解规律以后,我们来考虑具体怎么实现:

    首先我们要动态注册广播,那么我们怎么样才能在开机之后,马上就动态注册呢?

    显然开机广播只能使用静态注册的方式来监听,所以我注册一个广播用于监听开机广播,然后在该onReceive()方法中,创建一个service,再在这个service重新动态注册一个Receiver,优先级为2147483647

    这里注意两个问题,1是保证我们的应用首先接收到开机广播,根据上述原则,只能让我们的应用最先安装(这个当然没有办法保证),并且文件包排在最前面(这个要修改包名,所以我们做这类应用的时候,也要注意包名)

    2是保证我们的service长期存活,因为一旦service死掉,会造成动态注册的广播也死掉


    源码下载地址:

    接收广播的最高优先级


    根据上面的方法,原则上我们就能保证我们的app是第一个接收到短信广播的,当然这是在4.4系统以下,如果是4.4系统,请看下一篇文章!

    Android短信拦截机制适配的坑(下)--4.4以上系统,主要是6.0


    展开全文
  • 本页面部分内容是根据Google创建和共享作品进行的修改,并根据Creative Commons 3.0 Attribution License中所述条款进行使用。 ------------------------------- 版本更新详情 -----------------------------...
  • 6、 短信可保存在邮件客户端上:通过此产品发送和接收信息将保存在邮件客户端发送邮件”和“收件箱”中,方便用户反复使用和查找,同时可将短信内容的保存转移至邮件客户端上。 7、 分组发送功能:本产品可...
  • 6、 短信可保存在邮件客户端上:通过此产品发送和接收信息将保存在邮件客户端发送邮件”和“收件箱”中,方便用户反复使用和查找,同时可将短信内容的保存转移至邮件客户端上。 7、 分组发送功能:本产品可...
  • 3、后台可维护企业收到的简历、企业邀请面试和个人职位申请记录等数据; 4、系统新增设微简历功能,可快速创建简历投递职位,并同时支持完整简历和毕业生简历; 5、系统职位和简历搜索结果页支持按页码分页效果; ...
  • 今天一早,春节过,要针对用户的短信提醒内容进行变更。 发送短信,以及其他程序的逻辑早已经线上运行很久,故无需回归...我收到的短信是,您好,您的代金券¥{hours}小时有效。是的,一个短信而已,没有资损,但是

    今天一早,春节已过,要针对用户的短信提醒内容进行变更。

    发送短信,以及其他程序的逻辑早已经线上运行很久,故无需回归和确认,仅仅修改一下模板即可。


    我有个习惯,再简单的逻辑,东西,怎么样也要在上线前真真正正的看一遍,走一遍。


    所以 ,发现了变量hour,被粗心大意的设置为hours。

    我收到的短信是,您好,您的代金券¥{hours}小时有效。是的,一个短信而已,没有资损,但是,你要脸不?公司的脸呢?


    常在河边走,哪能不湿鞋,特别做测试这种高危的行业。


    所以,在重复一下

    节操:要上线的东西,必须最终走一遍。

    底线:不能说谎,以及侥幸心理。


    做测试快9年时间,前八年在外包公司一路上坡快做到头儿了,如今在互联网一线,突然感触良多。

    心中若有大侠梦,睡觉也要开着灯。


    以上。2016年02月15日20:01:20

    展开全文
  • 4)商品添加、修改、以及独创复制功能,支持名称价格、库存、积分等批量修改 商品批量删除、批量转移分类、设置推荐、设置特价、设置分类推荐等 5)价格批量处理:可以将整站商品价格加、减、乘、除一定值或者...
  • 办公自动化OA系统源码

    热门讨论 2010-03-30 10:22:04
    我的邮件:最新收到的邮件列表 我的文档:最新归档的项目文档 我的审批:待我审批的项目文档 考勤:成员上下班的考勤 全文检索:对系统中项目文档的全文检索,并有权限过滤机制 系统设置各类接点:系统的权限...
  • 我的邮件:最新收到的邮件列表 我的文档:最新归档的项目文档 我的审批:待我审批的项目文档 考勤:成员上下班的考勤 全文检索:对系统中项目文档的全文检索,并有权限过滤机制 系统设置各类接点:系统的权限...
  • 我的邮件:最新收到的邮件列表 我的文档:最新归档的项目文档 我的审批:待我审批的项目文档 考勤:成员上下班的考勤 全文检索:对系统中项目文档的全文检索,并有权限过滤机制 系统设置各类接点:系统的权限...
  • 我的邮件:最新收到的邮件列表 我的文档:最新归档的项目文档 我的审批:待我审批的项目文档 考勤:成员上下班的考勤 全文检索:对系统中项目文档的全文检索,并有权限过滤机制 系统设置各类接点:系统的权限中心和...
  • 我的邮件:最新收到的邮件列表 我的文档:最新归档的项目文档 我的审批:待我审批的项目文档 考勤:成员上下班的考勤 全文检索:对系统中项目文档的全文检索,并有权限过滤机制 系统设置各类接点:系统的权限...
  • 我的邮件:最新收到的邮件列表 我的文档:最新归档的项目文档 我的审批:待我审批的项目文档 考勤:成员上下班的考勤 全文检索:对系统中项目文档的全文检索,并有权限过滤机制 系统设置各类接点:系统的权限...
  • 在开发短信网关时,由于要对短信内容进行校验,拼签名等处理,因此在接收到短信分片后,要进行合并成一条处理,之后发送时再拆分为多条(当然有可能始终只收到一个片断,造成永远无法合并成一条完整的短信)。...
  •  用户发表求购信息和发布商品时需要先进行信息完善,用户可以查看自己发布商品,对发布商品进行修改或删除,查看发布求购信息,对求购商品进行修改或删除。 2 概要设计  系统整体结构流程图如下 ...
  • php OA 源码 办公自动化源码

    热门讨论 2010-10-29 00:51:15
    审批流程即可以采用固定流程,一个模板梆定一个流程方式,也可以设定允许在流转过程中自定义流程或修改已设定流程,流程支持直流、分流、并流、条件分支、流程嵌套以及各种协办、联办等复杂流程。 在审批中,...
  • 发布以天为形式商品项目(添加、删除、修改、编辑) 秒杀抢团项目 发布以秒为形式商品项目 商户展示 一、商家有自己简单介绍页面,介绍信息和产品 二、商家可以自己后台对商品券进行验证消费。 商家专卖店...
  • 短信服务监听MQ消息,收到消息后发送短信。 其它服务要发送短信时,通过MQ通知短信微服务。 2.13 文件上传微服务 使用分布式文件系统FastDFS实现图片上传。 FastDFS架构 FastDFS两个主要角色:Tracker Server...
  • 凭借骑士网络不断创新精神和认真工作态度,骑士人才系统成国内同类软件中最好用人才系统。 骑士cms人才系统 v4.1.23 bulid2017.02.17 更新内容: 修复 后台测试邮件发送失败提示问题 修复 后台‘邮件...
  • 淘宝fasp刷钻源码

    2013-11-23 22:19:20
    7、手机验证没收到信息可以重新发送,后台增加,可清理绑定手机 8、淘宝升级连接,导致平台有时候发布任务无法正常审核掌柜名,现2.5版已经升级 9、投诉申诉BUG已经解决 10、提现金额会四舍五入BUG 、进行了其它...
  • vc++ 应用源码包_1

    热门讨论 2012-09-15 14:22:12
    该实例可进行局域网聊天、一对多、多对一、和多对多传送和续传,理论上这是我本人实现目的,而且目前经测试基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit使用、最小到...
  • vc++ 应用源码包_6

    热门讨论 2012-09-15 14:59:46
    该实例可进行局域网聊天、一对多、多对一、和多对多传送和续传,理论上这是我本人实现目的,而且目前经测试基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit使用、最小到...
  • vc++ 应用源码包_2

    热门讨论 2012-09-15 14:27:40
    该实例可进行局域网聊天、一对多、多对一、和多对多传送和续传,理论上这是我本人实现目的,而且目前经测试基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit使用、最小到...
  • vc++ 应用源码包_5

    热门讨论 2012-09-15 14:45:16
    该实例可进行局域网聊天、一对多、多对一、和多对多传送和续传,理论上这是我本人实现目的,而且目前经测试基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit使用、最小到...
  • vc++ 应用源码包_4

    热门讨论 2012-09-15 14:38:35
    该实例可进行局域网聊天、一对多、多对一、和多对多传送和续传,理论上这是我本人实现目的,而且目前经测试基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit使用、最小到...
  • vc++ 应用源码包_3

    热门讨论 2012-09-15 14:33:15
    该实例可进行局域网聊天、一对多、多对一、和多对多传送和续传,理论上这是我本人实现目的,而且目前经测试基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit使用、最小到...

空空如也

空空如也

1 2 3
收藏数 47
精华内容 18
关键字:

修改已收到的短信内容