精华内容
下载资源
问答
  • 通知栏和来电拦截

    2013-09-01 20:07:48
    发来的信息显示通知栏中和把来的电话拦截.
  • 当我们希望某一应用的通知通知栏上提示时,我们可以通过xposed来实现拦截它的操作。以支付宝为例,当支付宝切换到后台时,信息会以通知栏的形式显示。若要拦截它,大致有两个思路来实现:1、反编译支付宝代码,...

    当我们不希望某一应用的通知在通知栏上提示时,我们可以通过xposed来实现拦截它的操作。以支付宝为例,当支付宝切换到后台时,信息会以通知栏的形式显示。若要拦截它,大致有两个思路来实现:1、反编译支付宝代码,将相关代码hook掉。然而这个工程对我等小码仔来说,太难实现。2、拦截系统所有的通知信息,对其进行过滤,当信息是来自我们想要拦截的应用时,hook掉它。本文记录一下对第二种方法的简单实现。
    基于面向google(baidu)编程,这里决定hook NotificationManager中notify方法,源码如下:

    /**  
     * Post a notification to be shown in the status bar. If a notification with  
     * the same tag and id has already been posted by your application and has not yet been   
     * canceled, it will be replaced by the updated information.  
     *  
     * @param tag A string identifier for this notification.  May be {@code null}.  
     * @param id An identifier for this notification.  The pair (tag, id) must be unique  
     *        within your application.  
     * @param notification A {@link Notification} object describing what to  
     *        show the user. Must not be null.  
     */  
    public void notify(String tag, int id, Notification notification)
    {   
        notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));  
    }
    

    notify方法的三个入参,其中notification就是要在通知栏上显示的信息。代码如下(测试时使用QQ来测试,所以注释中有QQ的包名):

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        if (!lpparam.packageName.equals("com.eg.android.AlipayGphone")
                && !lpparam.processName.equals("com.eg.android.AlipayGphone"))
            return;
        if (lpparam.packageName.equals("com.eg.android.AlipayGphone")) {
            //        if (!lpparam.packageName.equals("com.tencent.mobileqq")
            //                && !lpparam.processName.equals("com.tencent.mobileqq"))
            //            return;
            //        if (lpparam.packageName.equals("com.tencent.mobileqq")) {
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                XposedHelpers.findAndHookMethod("android.app.NotificationManager"
                        , lpparam.classLoader, "notify"
                        , String.class, int.class, Notification.class
                        , new XC_MethodHook() {
                            @Override
                            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                XposedBridge.log("methodHookParam.args:  " + Arrays.toString(param.args));
                                //通过param拿到第三个入参notification对象
                                Notification notification = (Notification) param.args[2];
                                //获得包名
                                String aPackage = notification.contentView.getPackage();
                                String title = "--";
                                String text = "--";
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                                    Bundle bundle = notification.extras;
                                    title = (String) bundle.get("android.title");
                                    text = (String) bundle.get("android.text");
                                }
                                //    if ("com.tencent.mobileqq".equals(aPackage)) {
                                if ("com.eg.android.AlipayGphone".equals(aPackage)
                                        && title.equals("支付宝消息") &&
                                        text.endsWith("已成功向你转了1笔钱")) {
                                    param.setResult(null);
                                    return;
                                }
                                super.beforeHookedMethod(param);
                            }
                        });
            }
    }
    

    上面代码实现的是拦截支付宝的到账通知(支付宝还会正常到账,打开支付宝后也会有到账消息,只是拦截了通知栏的提示不影响正常功能),通过notification.extra可以获得要显示在通知栏的信息内容。

        Bundle[{android.title=leon, android.subText=null,   android.showChronometer=false,   android.icon=2130837513, 
        android.text=leon:九分风好  大, android.progress=0,     android.progressMax=0,
        android.rebuild.contentViewActionCount=41,   android.showWhen=true,
        android.rebuild.applicationInfo=ApplicationInfo {1a3b2b0 com.eg.android.AlipayGphone},
        android.largeIcon=android.graphics.Bitmap@1810ab9, android.infoText=null, android.originatingUserId=0,
        android.progressIndeterminate=false}]  
    

    可以看到这是一个bundle对象,其中android.title是通知栏显示的标题,android.text是通知栏显示的内容。这条是支付宝接收到用户发送消息时的内容,下面看一下接收到转账提示时的内容。

        Bundle[{android.title=支付宝消息, android.subText=null, android.showChronometer=false, android.icon=2130837513,
        android.text=leon已成功向你转了1笔钱, android.progress=0, android.progressMax=0,
        android.rebuild.contentViewActionCount=41, android.showWhen=true,
        android.rebuild.applicationInfo=ApplicationInfo{1a3b2b0 com.eg.android.AlipayGphone},
        android.largeIcon=android.graphics.Bitmap@33eef20a, android.infoText=null,
        android.originatingUserId=0,android.progressIndeterminate=false}]  
    

    可以看到当信息来自支付宝转账时,android.title的内容固定为支付宝消息,android.text的内容为XXX已成功想你转了1笔钱,其余内容全部相同。我们就可以考虑判断这两个字段的值,来对到账消息进行拦截的同时不影响正常功能的使用。代码在上面,很简单的实现了对支付宝到账信息的拦截,若有需要对到账信息统计的话,可以在统计到账的次数与转账人,但是无法统计到账金额,毕竟只是对系统方法进行hook,支付宝也不会把金额信息给显示在通知栏中。

    展开全文
  • 在上篇文章中我们留下了...问题一由于我们写了自己的拦截器,默认的拦截起作用了。解决办法一 把默认拦截器加入到配置文件中 <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configurati

    上篇文章中我们留下了这个问题。在这里我们一点一点的解决。

    问题一

    由于我们写了自己的拦截器,默认的拦截器不起作用了。

    解决办法一

    把默认拦截器加入到配置文件中

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
        <!-- 开发者模式 -->
        <constant name="struts.devMode" value="true"></constant>
        <package name="user" extends="struts-default" namespace="/user">
            <!-- 声明自己定义的拦截器,名字以及对应的java类 -->
            <interceptors> 
                <interceptor name="myInterceptor" class="com.scx.web.intercepter.LoginIntercepter"></interceptor>
            </interceptors>
            <!-- 全局逻辑结果视图 -->
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
            <!-- 用户登录的操作方法 -->
            <action name="login" class="com.scx.web.action.UserAction" method="login">
                <result name="success" type="redirectAction">toMain</result>
            </action>
            <!-- 显示主页的操作方法 -->
            <action name="toMain" class="com.scx.web.action.UserAction" method="main">
                <!-- 默认拦截器配置进来 -->
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <!-- 自定义拦截器配置进来 -->
                <interceptor-ref name="myInterceptor"></interceptor-ref>
                <result name="success">/main.jsp</result>
            </action>
            <!-- 显示另一个页面的操作方法 -->
            <action name="toOther" class="com.scx.web.action.UserAction" method="other">
                <!-- 默认拦截器配置进来 -->
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <!-- 自定义拦截器配置进来 -->
                <interceptor-ref name="myInterceptor"></interceptor-ref>
                <result name="success">/other.jsp</result>
            </action>
        </package>
    </struts>

    问题二

    解决方法一中存在的问题:当有多个拦截器,多个action动作时,需要配置的地方太多。

    解决办法二

    抽取公共的包,把全局配置放入公共包中

    每次我们在Struts.xml编写包时都会将其继承于struts-default,这是struts2核心jar包里面为我们提供的。
    这里写图片描述
    想去看的同学可以解压Struts2的核心包, 里面有struts-default.xml,打开就能看到,第128行。
    这里的继承和javase里面的继承一样,我们当然也可以继承于自己新建的包,有个前提就是,我们新建的包一定要是抽象的,即未配置任何action动作。
    一定要仔细看注释,否则可能看不懂。
    简而言之就是:

    • 我们新建了一个名为my-default的package 继承于struts-default
    • 我们在my-default包里面配置我们的自定义拦截器栈myDefaultStack,引入自定义的拦截器和系统默认的拦截器栈
    • 在action动作的包继承于my-default。在主页和其它页面的action动作里添加我们自定义的拦截器栈myDefaultStack
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
        <!-- 开发者模式 -->
        <constant name="struts.devMode" value="true"></constant>
        <package name="my-default" abstract="true" extends="struts-default">    
            <interceptors> 
                <!-- 声明自己定义的拦截器,名字以及对应的java类 -->
                <interceptor name="myInterceptor" class="com.scx.web.intercepter.LoginIntercepter"></interceptor>
                <!-- 自定义的拦截器栈 -->
                <interceptor-stack name="myDefaultStack">
                    <!-- 配置自己定义的拦截器 -->
                    <interceptor-ref name="myInterceptor"></interceptor-ref>
                    <!-- 配置默认的拦截器栈 -->
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
            <!-- 全局逻辑结果视图 -->
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
        </package>
        <!-- 继承于上面的my-default -->
        <package name="user" extends="my-default" namespace="/user">
            <!-- 用户登录的操作方法 -->
            <action name="login" class="com.scx.web.action.UserAction" method="login">
                <result name="success" type="redirectAction">toMain</result>
            </action>
            <!-- 显示主页的操作方法 -->
            <action name="toMain" class="com.scx.web.action.UserAction" method="main">
                <!-- 引入自定义的拦截器栈  name和上面我们自定义的拦截器栈名相对应-->
                <interceptor-ref name="myDefaultStack"></interceptor-ref>
                <result name="success">/main.jsp</result>
            </action>
            <!-- 显示另一个页面的操作方法 -->
            <action name="toOther" class="com.scx.web.action.UserAction" method="other">
                <!-- 引入自定义的拦截器栈  name和上面我们自定义的拦截器栈名相对应-->
                <interceptor-ref name="myDefaultStack"></interceptor-ref>
                <result name="success">/other.jsp</result>
            </action>
        </package>
    </struts>

    这样似乎解决了很多拦截器的问题,但是还没解决很多action动作仍然需要配置的问题,到底能不能不配置呢?

    问题三

    解决方法二还没解决很多action动作仍然需要配置的问题,到底能不能不配置呢?

    解决办法三

    思路:我们在设置【开发模式】时,覆盖掉了一个default.properties中的常量,能不能把struts-default.xml中的默认拦截器栈的设置给覆盖掉呢?答案是可以的。
    同样也是在struts-default.xml中可以找到这行代码
    这里写图片描述

    • 在my-default包里面设置默认的拦截器栈
    • 删除解决方法二action里面配置的自定义拦截器栈

    配置后的代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
        <!-- 开发者模式 -->
        <constant name="struts.devMode" value="true"></constant>
        <package name="my-default" abstract="true" extends="struts-default">    
            <interceptors> 
                <!-- 声明自己定义的拦截器,名字以及对应的java类 -->
                <interceptor name="myInterceptor" class="com.scx.web.intercepter.LoginIntercepter"></interceptor>
                <!-- 自定义的拦截器栈 -->
                <interceptor-stack name="myDefaultStack">
                    <!-- 配置自己定义的拦截器 -->
                    <interceptor-ref name="myInterceptor"></interceptor-ref>
                    <!-- 配置默认的拦截器栈 -->
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
            <!-- 设置默认拦截器 -->
            <default-interceptor-ref name="myDefaultStack"/>
            <!-- 全局逻辑结果视图 -->
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
    
        </package>
        <!-- 继承于上面的my-default -->
        <package name="user" extends="my-default" namespace="/user">
            <!-- 用户登录的操作方法 -->
            <action name="login" class="com.scx.web.action.UserAction" method="login">
                <result name="success" type="redirectAction">toMain</result>
            </action>
            <!-- 显示主页的操作方法 -->
            <action name="toMain" class="com.scx.web.action.UserAction" method="main">
                <result name="success">/main.jsp</result>
            </action>
            <!-- 显示另一个页面的操作方法 -->
            <action name="toOther" class="com.scx.web.action.UserAction" method="other">
                <result name="success">/other.jsp</result>
            </action>
        </package>
    </struts>

    这样配置 似乎我们完成了我们的目标,无论有多少个自定义拦截器都可以配置到my-default包里面,无论都多少个action只要它继承于my-default就可以。可是你有没有发现,这样连我们的登录页面也被拦截了。
    问题真是一个接着一个出现 。累觉不爱啊
    这里写图片描述

    问题四

    解决方法三把我们的登录界面都被拦截了

    解决办法四

    需要通过AbstractInterceptor类的子类入手,通过查看发现,该类还有一个子类是抽象的
    这里写图片描述


    • excludeMethods配置哪些动作方法不拦截
    • includeMethods配置那些动作方法拦截
      我们都可以在struts.xml中通过注入的方式进行配置。根据自己的需求为不同的参数注入。

    所以我们在自定义拦截器时,还可以继承MethodFilterInterceptor并且重写doIntercept方法。
    这里写图片描述
    在struts.xml配置的部分代码如下
    这里写图片描述
    运行似乎没有问题。
    还是有个问题 不知道大家有没有发现
    我们是在my-default里面配置哪些方法需要拦截,哪些方法不需要拦截。但是在没有写动作类和动作方法之前,不确定方法名叫什么。

    问题五

    我们在声明时配置了哪些方法需要拦截,哪些方法不需要拦截。但是在没有写动作类和动作方法之前,不确定方法名叫什么。

    解决办法五

    我们可以在需要使用拦截器的时候给它注入参数。
    这里写图片描述

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
        <!-- 开发者模式 -->
        <constant name="struts.devMode" value="true"></constant>
        <package name="my-default" abstract="true" extends="struts-default">    
            <interceptors> 
                <!-- 声明自己定义的拦截器,名字以及对应的java类 -->
                <interceptor name="myInterceptor" class="com.scx.web.intercepter.LoginIntercepter"></interceptor>
                <!-- 自定义的拦截器栈 -->
                <interceptor-stack name="myDefaultStack">
                    <!-- 配置自己定义的拦截器 -->
                    <interceptor-ref name="myInterceptor"></interceptor-ref>
                    <!-- 配置默认的拦截器栈 -->
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
            <!-- 设置默认拦截器 -->
            <default-interceptor-ref name="myDefaultStack"/>
            <!-- 全局逻辑结果视图 -->
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
    
        </package>
        <!-- 继承于上面的my-default -->
        <package name="user" extends="my-default" namespace="/user">
            <!-- 用户登录的操作方法 -->
            <action name="login" class="com.scx.web.action.UserAction" method="login">
                <interceptor-ref name="myDefaultStack">
                    <!-- 在使用拦截器时给拦截器注入参数 -->
                    <param name="myInteceptor.excludeMethods">login</param>
                </interceptor-ref>
                <result name="success" type="redirectAction">toMain</result>
            </action>
            <!-- 显示主页的操作方法 -->
            <action name="toMain" class="com.scx.web.action.UserAction" method="main">
                <result name="success">/main.jsp</result>
            </action>
            <!-- 显示另一个页面的操作方法 -->
            <action name="toOther" class="com.scx.web.action.UserAction" method="other">
                <result name="success">/other.jsp</result>
            </action>
        </package>
    </struts>

    到此全部结束。。
    这里写图片描述

    展开全文
  • 如何拦截通知 为了拦截android系统收到的通知,我们需要在系统的后台运行特定的服务。该服务称为: NotificationListenerService 。 该服务的基本作用是:将其注册到android系统,然后在发布或删除新通知或更改其...
  • ①AOP的前置通知方法 、后置通知方法 、环绕通知方法 首先导入相关的包: (1)定义一个java文件来使用AOP技术。(LogAdvice.java(日志通知切面)) LogAdvice.java package com . advice ; import ...

    AOP(Aspect Oriented Programming)也就是面向切面编程的技术。AOP基于IoC基础,是对OOP的有益补充。AOP是代码之间解耦的一 种实现。可以这样理解,面向对象编程是从静态角度考虑程序结构,面向切面编程是从动态角度考虑程序运行过程。AOP将应用系统分为两部分:
    (1)核心业务逻辑(Core Business Concerns)。
    (2)横向的通用逻辑,也就是所谓的切面(Crosscutting Enterprise Concerns)。
    例如,所有大中型应用都要涉及的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。

    AOP的底层实现原理实际是Java语言的动态代理机制。AOP 代理是由AOP框架动态生成一个对象,该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法,但代理中的方法与目标对象的方法存在差异: AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。Spring 的AOP通常和IoC配合使用,需要程序员参与的有3个部分:
    (1)定义普通业务组件。
    (2)定义切入点。一个切入点可以横切多个业务组件。
    (3)定义增强处理。增强处理就是在AOP框架为普通业务组件织入的处理动作。
    Spring有如下两种方式来定义切入点和增强处理:
    (1)annotation 配置方式。使用@Aspect、 @Pointcut 等Annotation标注切入点和增强处理。
    (2)xml 配置方式。使用xml配置文件定义切入点和增强处理。


    我使用的是上一个学习crud操作的代码(MVC),稍作修改完成这个知识点的学习。
    使用Spring实现mysql数据库的CRUD操作

    ①AOP的前置通知方法 、后置通知方法 、环绕通知方法

    首先导入相关的包:
    在这里插入图片描述

    (1)定义一个java文件来使用AOP技术。(LogAdvice.java(日志通知切面))

    LogAdvice.java

    package com.advice;
    
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    
    
    public class LogAdvice {
    	//前置通知方法
    	public void myBeforeAdvice(JoinPoint joinPoint){
    		String methodname = joinPoint.getSignature().getName();
            System.out.println("Before前置通知——执行"+methodname+"方法前");
        }
    	
    	//后置通知方法
        public void myAfterAdvice(JoinPoint joinPoint){
        	String methodname = joinPoint.getSignature().getName();
            System.out.println("执行"+methodname+"方法后——After后置通知");
        }
        
        //环绕通知方法
        public void myAroundAdvice(ProceedingJoinPoint point) throws Throwable{
        	String methodname = point.getSignature().getName();
        	System.out.println("环绕通知,执行"+methodname+"方法前");
            //选择执行
            point.proceed();
            System.out.println("环绕通知,执行"+methodname+"方法后");
        }
    }
    

    (2)在applicationContext.xml文件做相关bean配置(部分代码)

    <bean id="userDao" class="com.dao.UserDao"/>
        <bean id="userService" class="com.service.UserService">
        	<property name="userDao" ref="service"></property>
        </bean>
        <bean id="logAdvice" class="com.advice.LogAdvice"/>
        
        <aop:config>
           <!-- 配置一个切面 -->
           <aop:aspect id="logaop" ref="logAdvice" order="1">
               <!-- 定义切入点,表示对service的所有方法都进行拦截 -->
               <!-- 
               expression:用来匹配执行方法的连接点
               	第一个*表示匹配任意的方法的返回值
               	第一个..表示service包及其子包
               	第二个*表示所有类
               	第三个*表示所有方法
               	第二个..表示方法的任意参数个数
                -->
               <aop:pointcut expression="execution(* com.service.*.*(..))" id="testpointcut"/>
               <!-- 定义前置通知 -->
               <aop:before method="myBeforeAdvice" pointcut-ref="testpointcut"/>
               <!-- 定义后置通知 -->
               <aop:after method="myAfterAdvice" pointcut-ref="testpointcut"/>
               <!-- 定义环绕通知 -->           
               <aop:around method="myAroundAdvice" pointcut-ref="testpointcut"/>
           </aop:aspect>
        </aop:config>
    </beans>
    

    再写个测试类跑起来就可以了。


    ②通过拦截器判断用户是否可以执行目标代码的方法

    (1)AuthorityInterceptor.java(用户权限拦截器)
    功能:
    admin用户可以执行add()和update()方法
    register用户可以执行add()方法,但不可执行update()方法
    other用户都不可以执行add()和update()方法

    package com.interceptor;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    import com.bean.User;
    
    public class AuthorityInterceptor implements MethodInterceptor {
    
    	private User user;
    	public User getUser() {
    		return user;
    	}
    	public void setUser(User user) {
    		this.user = user;
    	}
    	
    	public Object invoke(MethodInvocation arg0) throws Throwable {
    		// TODO Auto-generated method stub
    		System.out.println("拦截器==权限验证开始");
    		String username=this.user.getUsername();
    		String methodName = arg0.getMethod().getName();
    		if(!username.equals("admin")&&!username.equals("register")) {
    			System.out.println("没有任何执行权限");
    			return null;
    		}
    		else if(username.equals("register")&&methodName.equals("update")) {
    			System.out.println("register用户没有修改权限");
    			return null;
    		}
    		else {
    			Object object = arg0.proceed();
    			System.out.println("拦截器==权限验证结束");
    			return object;
    		}
    	}
    
    }
    

    (2)LogInterceptor.java(用户操作日志拦截器)

    package com.interceptor;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class LogInterceptor implements MethodInterceptor {
    
    	public Object invoke(MethodInvocation arg0) throws Throwable {
    		// TODO Auto-generated method stub
    		String methodName = arg0.getMethod().getName();
    		Object object = arg0.proceed();
    		System.out.println("拦截器==日志记录:尝试执行"+methodName+"方法");
    		return object;
    	}
    }
    

    (3)在applicationContext.xml文件做相关bean配置(部分代码)

       <bean id="admin" class="com.bean.User">
      		<property name="username" value="admin"></property>
      		<property name="password" value="123456"></property>
      	</bean>
      	
      	<bean id="register" class="com.bean.User">
      		<property name="username" value="register"></property>
      		<property name="password" value="654321"></property>
      	</bean>
      	
      	<bean id="other" class="com.bean.User">
      		<property name="username" value="other"></property>
      		<property name="password" value="666666"></property>
      	</bean>
      	<!--  -->
      	<bean id="logInterceptor" class="com.interceptor.LogInterceptor"/>
      	
      	<bean id="authorityInterceptor" class="com.interceptor.AuthorityInterceptor">
      		<!-- admin/register/other -->
      		<property name="user" ref="admin"></property>
      	</bean>
      	
      	<bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
      		<property name="target" ref="userDao"></property>
      		<property name="interceptorNames">
      			<list>
      				<value>authorityInterceptor</value>
      				<value>logInterceptor</value>
      			</list>
      		</property>
      	</bean>
    

    激动人心的时刻到了,我们把成品跑起来!

    测试类:

    package com.test;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.service.UserService;
    
    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    
    		ClassPathXmlApplicationContext l = new ClassPathXmlApplicationContext("applicationContext.xml");
    		
    		UserService service = l.getBean("userService",UserService.class);
    		
    		
    		service.add();
    		l.close();//关闭流
    		service.update();
    		l.close();
    	}
    
    }
    

    applicationContext.xml(完整代码)

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        <bean id="admin" class="com.bean.User">
      		<property name="username" value="admin"></property>
      		<property name="password" value="123"></property>
      	</bean>
      	
      	<bean id="register" class="com.bean.User">
      		<property name="username" value="register"></property>
      		<property name="password" value="123"></property>
      	</bean>
      	
      	<bean id="other" class="com.bean.User">
      		<property name="username" value="other"></property>
      		<property name="password" value="123"></property>
      	</bean>
      	<!--  -->
      	<bean id="logInterceptor" class="com.interceptor.LogInterceptor"/>
      	
      	<bean id="authorityInterceptor" class="com.interceptor.AuthorityInterceptor">
      		<!-- admin/register/other -->
      		<property name="user" ref="admin"></property>
      	</bean>
      	
      	<bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
      		<property name="target" ref="userDao"></property>
      		<property name="interceptorNames">
      			<list>
      				<value>authorityInterceptor</value>
      				<value>logInterceptor</value>
      			</list>
      		</property>
      	</bean>
        
        <bean id="userDao" class="com.dao.UserDao"/>
        <bean id="userService" class="com.service.UserService">
        	<property name="userDao" ref="service"></property>
        </bean>
        <bean id="logAdvice" class="com.advice.LogAdvice"/>
        
        <aop:config>
           <!-- 配置一个切面 -->
           <aop:aspect id="logaop" ref="logAdvice" order="1">
               <!-- 定义切入点,表示对service的所有方法都进行拦截 -->
               <!-- 
               expression:用来匹配执行方法的连接点
               	第一个*表示匹配任意的方法的返回值
               	第一个..表示service包及其子包
               	第二个*表示所有类
               	第三个*表示所有方法
               	第二个..表示方法的任意参数个数
                -->
               <aop:pointcut expression="execution(* com.service.*.*(..))" id="testpointcut"/>
               <!-- 定义前置通知 -->
               <aop:before method="myBeforeAdvice" pointcut-ref="testpointcut"/>
               <!-- 定义后置通知 -->
               <aop:after method="myAfterAdvice" pointcut-ref="testpointcut"/>
               <!-- 定义环绕通知 -->           
               <aop:around method="myAroundAdvice" pointcut-ref="testpointcut"/>
           </aop:aspect>
        </aop:config>
    </beans>
    

    修改xml文件的联系用户id来显示不同用户下的打印结果。

      	<bean id="authorityInterceptor" class="com.interceptor.AuthorityInterceptor">
      		<!-- admin/register/other -->
      		<property name="user" ref="admin"></property>
      	</bean>
    

    (1)admin
    在这里插入图片描述
    (2)register
    在这里插入图片描述
    (3)other
    在这里插入图片描述

    展开全文
  • 1.当通知权限被关闭时在华为等手机上Toast不显示; 2.Toast的队列机制在不同手机上可能会相同; 3.Toast的BadTokenException问题; 当发现系统Toast存在问题时,不少同学都会采用自定义的TYPE_TOAST弹窗来实现...

    先看看使用系统Toast存在的问题:

    1.当通知权限被关闭时在华为等手机上Toast不显示;
    
    2.Toast的队列机制在不同手机上可能会不相同;
    
    3.Toast的BadTokenException问题;

    当发现系统Toast存在问题时,不少同学都会采用自定义的TYPE_TOAST弹窗来实现相同效果。虽然大部分情况下效果都是 OK的,但其实TYPE_TOAST弹窗依然存在兼容问题:

    4.Android8.0之后的token null is not valid问题(实测部分机型问题);
    
    5.Android7.1之后,不允许同时展示两个TYPE_TOAST弹窗(实测部分机型问题)。

    那么,DToast使用的解决方案是:

    1.通知权限未被关闭时,使用SystemToast(修复了问题2和问题3的系统Toast);
    2.通知权限被关闭时,使用DovaToast(自定义的TYPE_TOAST弹窗);
    3.当使用DovaToast出现token null is not valid时,尝试使用ActivityToast(自定义的TYPE_APPLICATION_ATTACHED_DIALOG
    弹窗,只有当传入Context为Activity时,才会启用ActivityToast).

    相信不少同学旧项目中封装的ToastUtil都是直接使用的ApplicationContext作为上下文,然后在需要弹窗的时候直接就是ToastUtil.show(str) ,这样的使用方式对于我们来说是最方便的啦。

    当然,使用DToast你也依然可以沿用这种封装方式,但这种方式在下面这个场景中可能会无法成功展示出弹窗(该场景下原生Toast也一样无法弹出), 不过请放心不会导致应用崩溃,而且这个场景出现的概率较小,有以下三个必要条件:1.通知栏权限被关闭(通知栏权限默认都是打开的) 2.非MIUI手机 3.Android8.0以上的部分手机(我最近测试中的几部8.0+设备都不存在该问题)。

    不过,如果想要保证在所有场景下都能正常展示弹窗,还是建议在DToast.make(context)时传入Activity作为上下文,这样在该场景下DToast会启用ActivityToast展示出弹窗。

    接下来再详细分析下上面提到的五个问题:

    问题一:关闭通知权限时Toast不显示

    看下方Toast源码中的show()方法,通过AIDL获取到INotificationManager,并将接下来的显示流程控制权
    交给NotificationManagerService。
    NMS中会对Toast进行权限校验,当通知权限校验不通过时,Toast将不做展示。
    当然不同ROM中NMS可能会有不同,比如MIUI就对这部分内容进行了修改,所以小米手机关闭通知权限不会导致Toast不显示。
    
      /**
         * Show the view for the specified duration.
         */
        public void show() {
            if (mNextView == null) {
                throw new RuntimeException("setView must have been called");
            }
    
            INotificationManager service = getService();
            String pkg = mContext.getOpPackageName();
            TN tn = mTN;
            tn.mNextView = mNextView;
    
            try {
                service.enqueueToast(pkg, tn, mDuration);
            } catch (RemoteException e) {
                // Empty
            }
        }

    如何解决这个问题?只要能够绕过NotificationManagerService即可。

    DovaToast通过使用TYPE_TOAST实现全局弹窗功能,不使用系统Toast,也没有使用NMS服务,因此不受通知权限限制。

    问题二:系统Toast的队列机制在不同手机上可能会不相同

     我找了四台设备,创建两个Gravity不同的Toast并调用show()方法,结果出现了四种展示效果:
    
            * 荣耀5C-android7.0(只看到展示第一个Toast)
            * 小米8-MIUI10(只看到展示第二个Toast,即新的Toast.show会中止当前Toast的展示)
            * 红米6pro-MIUI9(两个Toast同时展示)
            * 荣耀5C-android6.0(第一个TOAST展示完成后,第二个才开始展示)

    造成这个问题的原因应该是各大厂商ROM中NMS维护Toast队列的逻辑有差异。 同样的,DToast内部也维护着自己的队列逻辑,保证在所有手机上使用DToast的效果相同。

     DToast中多个弹窗连续出现时:
    
            1.相同优先级时,会终止上一个,直接展示后一个;
            2.不同优先级时,如果后一个的优先级更高则会终止上一个,直接展示后一个。

    问题三:系统Toast的BadTokenException问题

    • Toast有个内部类 TN(extends ITransientNotification.Stub),调用Toast.show()时会将TN传递给NMS;

        public void show() {
            if (mNextView == null) {
                throw new RuntimeException("setView must have been called");
            }
            INotificationManager service = getService();
            String pkg = mContext.getOpPackageName();
            TN tn = mTN;
            tn.mNextView = mNextView;
            try {
                service.enqueueToast(pkg, tn, mDuration);
            } catch (RemoteException e) {
                // Empty
            }
        }
    • 在NMS中会生成一个windowToken,并将windowToken给到WindowManagerService,WMS会暂时保存该token并用于之后的校验;

      NotificationManagerService.java #enqueueToast源码:

            synchronized (mToastQueue) {
                int callingPid = Binder.getCallingPid();
                long callingId = Binder.clearCallingIdentity();
                try {
                    ToastRecord record;
                    int index = indexOfToastLocked(pkg, callback);
                    // If it's already in the queue, we update it in place, we don't
                    // move it to the end of the queue.
                    if (index >= 0) {
                        record = mToastQueue.get(index);
                        record.update(duration);
                    } else {
                        // Limit the number of toasts that any given package except the android
                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
                        if (!isSystemToast) {
                            int count = 0;
                            final int N = mToastQueue.size();
                            for (int i=0; i<N; i++) {
                                 final ToastRecord r = mToastQueue.get(i);
                                 if (r.pkg.equals(pkg)) {
                                     count++;
                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
                                         Slog.e(TAG, "Package has already posted " + count
                                                + " toasts. Not showing more. Package=" + pkg);
                                         return;
                                     }
                                 }
                            }
                        }
      
                        Binder token = new Binder();//生成一个token
                        mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
                        mToastQueue.add(record);
                        index = mToastQueue.size() - 1;
                        keepProcessAliveIfNeededLocked(callingPid);
                    }
                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
                    // new or just been updated.  Call back and tell it to show itself.
                    // If the callback fails, this will remove it from the list, so don't
                    // assume that it's valid after this.
                    if (index == 0) {
                        showNextToastLocked();
                    }
                } finally {
                    Binder.restoreCallingIdentity(callingId);
                }
            }
    • 然后NMS通过调用TN.show(windowToken)回传token给TN;

            /**
             * schedule handleShow into the right thread
             */
            @Override
            public void show(IBinder windowToken) {
                if (localLOGV) Log.v(TAG, "SHOW: " + this);
                mHandler.obtainMessage(SHOW, windowToken).sendToTarget();
            }
    • TN使用该token尝试向WindowManager中添加Toast视图(mParams.token = windowToken);

      在API25的源码中,Toast的WindowManager.LayoutParams参数新增了一个token属性,用于对添加的窗口进行校验。

     

     

     

    • 当param.token为空时,WindowManagerImpl会为其设置 DefaultToken;

        @Override
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
      
        private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {
            // Only use the default token if we don't have a parent window.
            if (mDefaultToken != null && mParentWindow == null) {
                if (!(params instanceof WindowManager.LayoutParams)) {
                    throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
                }
                // Only use the default token if we don't already have a token.
                final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
                if (wparams.token == null) {
                    wparams.token = mDefaultToken;
                }
            }
        }
    • 当WindowManager收到addView请求后会检查 mParams.token 是否有效,若有效则添加窗口展示,否则抛出BadTokenException异常.

                  switch (res) {
                      case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                      case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- token " + attrs.token
                                  + " is not valid; is your activity running?");
                      case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- token " + attrs.token
                                  + " is not for an application");
                      case WindowManagerGlobal.ADD_APP_EXITING:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- app for token " + attrs.token
                                  + " is exiting");
                      case WindowManagerGlobal.ADD_DUPLICATE_ADD:
                          throw new WindowManager.BadTokenException(
                                  "Unable to add window -- window " + mWindow
                                  + " has already been added");
                      case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
                          // Silently ignore -- we would have just removed it
                          // right away, anyway.
                          return;
                      case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
                          throw new WindowManager.BadTokenException("Unable to add window "
                                  + mWindow + " -- another window of type "
                                  + mWindowAttributes.type + " already exists");
                      case WindowManagerGlobal.ADD_PERMISSION_DENIED:
                          throw new WindowManager.BadTokenException("Unable to add window "
                                  + mWindow + " -- permission denied for window type "
                                  + mWindowAttributes.type);
                      case WindowManagerGlobal.ADD_INVALID_DISPLAY:
                          throw new WindowManager.InvalidDisplayException("Unable to add window "
                                  + mWindow + " -- the specified display can not be found");
                      case WindowManagerGlobal.ADD_INVALID_TYPE:
                          throw new WindowManager.InvalidDisplayException("Unable to add window "
                                  + mWindow + " -- the specified window type "
                                  + mWindowAttributes.type + " is not valid");
                  }

    什么情况下windowToken会失效?

    UI线程发生阻塞,导致TN.show()没有及时执行,当NotificationManager的检测超时后便会删除WMS中的该token,即造成token失效。

    如何解决?

    Google在API26中修复了这个问题,即增加了try-catch:
    
                // Since the notification manager service cancels the token right
                // after it notifies us to cancel the toast there is an inherent
                // race and we may attempt to add a window after the token has been
                // invalidated. Let us hedge against that.
                try {
                    mWM.addView(mView, mParams);
                    trySendAccessibilityEvent();
                } catch (WindowManager.BadTokenException e) {
                    /* ignore */
                }

    因此对于8.0之前的我们也需要做相同的处理。DToast是通过反射完成这个动作,具体看下方实现:

      //捕获8.0之前Toast的BadTokenException,Google在Android 8.0的代码提交中修复了这个问题
         private void hook(Toast toast) {
             try {
                 Field sField_TN = Toast.class.getDeclaredField("mTN");
                 sField_TN.setAccessible(true);
                 Field sField_TN_Handler = sField_TN.getType().getDeclaredField("mHandler");
                 sField_TN_Handler.setAccessible(true);
    
                 Object tn = sField_TN.get(toast);
                 Handler preHandler = (Handler) sField_TN_Handler.get(tn);
                 sField_TN_Handler.set(tn, new SafelyHandlerWrapper(preHandler));
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
    
    
         public class SafelyHandlerWrapper extends Handler {
             private Handler impl;
    
             public SafelyHandlerWrapper(Handler impl) {
                 this.impl = impl;
             }
    
             @Override
             public void dispatchMessage(Message msg) {
                 try {
                     impl.dispatchMessage(msg);
                 } catch (Exception e) {
                 }
             }
    
             @Override
             public void handleMessage(Message msg) {
                 impl.handleMessage(msg);//需要委托给原Handler执行
             }
         }

    问题四:Android8.0之后的token null is not valid问题

    Android8.0后对WindowManager做了限制和修改,特别是TYPE_TOAST类型的窗口,必须要传递一个token用于校验。

    API25:(PhoneWindowManager.java源码)

    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
        int type = attrs.type;
    
        outAppOp[0] = AppOpsManager.OP_NONE;
    
        if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
                || (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)
                || (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {
            return WindowManagerGlobal.ADD_INVALID_TYPE;
        }
    
        if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
            // Window manager will make sure these are okay.
            return WindowManagerGlobal.ADD_OKAY;
        }
        String permission = null;
        switch (type) {
            case TYPE_TOAST:
                // XXX right now the app process has complete control over
                // this...  should introduce a token to let the system
                // monitor/control what they are doing.
                outAppOp[0] = AppOpsManager.OP_TOAST_WINDOW;
                break;
            case TYPE_DREAM:
            case TYPE_INPUT_METHOD:
            case TYPE_WALLPAPER:
            case TYPE_PRIVATE_PRESENTATION:
            case TYPE_VOICE_INTERACTION:
            case TYPE_ACCESSIBILITY_OVERLAY:
            case TYPE_QS_DIALOG:
                // The window manager will check these.
                break;
            case TYPE_PHONE:
            case TYPE_PRIORITY_PHONE:
            case TYPE_SYSTEM_ALERT:
            case TYPE_SYSTEM_ERROR:
            case TYPE_SYSTEM_OVERLAY:
                permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
                outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
                break;
            default:
                permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
        }
        if (permission != null) {
            ...
        }
        return WindowManagerGlobal.ADD_OKAY;
    }

    API26:(PhoneWindowManager.java源码)

    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
        int type = attrs.type;
    
        outAppOp[0] = AppOpsManager.OP_NONE;
    
        if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
                || (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)
                || (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {
            return WindowManagerGlobal.ADD_INVALID_TYPE;
        }
    
        if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
            // Window manager will make sure these are okay.
            return ADD_OKAY;
        }
    
        if (!isSystemAlertWindowType(type)) {
            switch (type) {
                case TYPE_TOAST:
                    // Only apps that target older than O SDK can add window without a token, after
                    // that we require a token so apps cannot add toasts directly as the token is
                    // added by the notification system.
                    // Window manager does the checking for this.
                    outAppOp[0] = OP_TOAST_WINDOW;
                    return ADD_OKAY;
                case TYPE_DREAM:
                case TYPE_INPUT_METHOD:
                case TYPE_WALLPAPER:
                case TYPE_PRESENTATION:
                case TYPE_PRIVATE_PRESENTATION:
                case TYPE_VOICE_INTERACTION:
                case TYPE_ACCESSIBILITY_OVERLAY:
                case TYPE_QS_DIALOG:
                    // The window manager will check these.
                    return ADD_OKAY;
            }
            return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
                    == PERMISSION_GRANTED ? ADD_OKAY : ADD_PERMISSION_DENIED;
        }
    }

    为了解决问题一,DovaToast不得不选择绕过NotificationManagerService的控制,但由于windowToken是NMS生成的, 绕过NMS就无法获取到有效的windowToken,于是作为TYPE_TOAST的DovaToast就可能陷入第四个问题。因此,DToast选择在DovaToast出现 该问题时引入ActivityToast,在DovaToast无法正常展示时创建一个依附于Activity的弹窗展示出来,不过ActivityToast只会展示在当前Activity,不具有跨页面功能。 如果说有更好的方案,那肯定是去获取悬浮窗权限然后改用TYPE_PHONE等类型,但悬浮窗权限往往不容易获取,目前来看恐怕除了微信其他APP都不能保证拿得到用户的悬浮窗权限。

    问题五:Android7.1之后,不允许同时展示两个TYPE_TOAST弹窗

    DToast的弹窗策略就是同一时间最多只展示一个弹窗,逻辑上就避免了此问题。因此仅捕获该异常。

    TODO LIST:

    • 增加适配应用已获取到悬浮窗权限的情况
    • 考虑是否需要支持同时展示多个弹窗

    其他建议

    • 新项目做应用架构的时候可以考虑把整个应用(除闪屏页等特殊界面外)做成只有一个Activity,其他全是Fragment,这样就不存在悬浮窗的问题啦。
    • 如果能够接受Toast不跨界面的话,建议使用SnackBar

    最后附上自己封装好的moudle库,希望对每个人有用!----》https://download.csdn.net/download/small_and_smallworld/10831796

    展开全文
  • 截获系统广播,读取消息,若联系人存在于通信录中,则让消息继续传播;若属于陌生号码,则中断消息,同时把信息显示在自己的程序中。
  •  // 拦截所有页面跳转,可使用参数拦截.apk的跳转  wv. overrideUrlLoading ({ mode: 'reject', match: '.*\.apk.*' }, function(e) {  wLoading = plus.nativeUI.showWaiting(" 开始下载... ");    ...
  • 彩信拦截

    千次阅读 2015-02-05 17:41:43
    如何拦截到彩信并同时读取彩信的内容?之前一直不知怎么办。经过好几天的摸索、借鉴,总算搞明白了。发到网上,与大家分享! 简单说一下思路: 1、 注册一个广播,优先值为1000(这样才能先于系统收到广播),并在...
  • 问题描述:在controller层用AOP拦截自定义注解,结果虽然报错,前端却获取到controller层里的方法返回的结果。切面里写了前置通知、环绕通知和后置通知,断点调试,在后置通知里没有获取到返回结果。多次检查后...
  • IOS event 拦截

    千次阅读 2013-04-15 22:47:35
    From:RuiQ's自留地 项目里有一个需求,类似新浪或者腾讯微博的顶部title栏的类别选择器的消失(在选择器展开的时候,触摸屏幕任何地方...可是这个方案实现起来非常麻烦,也优雅,而且发现button拦截不到scr
  •  监听器(Listener):其实功能与拦截器是相似的,但它实现原理不同,它是为每一个事件注册一个或多个监听器,一旦事件发生,则事件源通知所有监听该事件的监听器,然后监听器处理通知(观察者模式)。 ----------...
  • 屏蔽系统通知,Toast无法显示的解决方案 v2.0.0
  • View的事件拦截机制浅析

    千次阅读 2017-08-04 10:03:21
    换句话说,不是那些作者懂。只是说,他懂了,但他讲解后一定能让别人看得懂。我记得有人问我当初是怎么接触自定义view这东西的。因为他们觉得自定义view这个东西很难。我就回了如下几句话:自定义view你把pa
  • 猜测有可能是用户小心添加过滤了或者其他版本会有拦截,导致编码器被关闭无法正确编码。查找资源后发现,弹窗拦截是通过发送Windows消息触发隐藏和关闭的。 于是考虑先把编码器生成后接受到的消息打印出来查看分析...
  • 支付宝异步通知不被调用

    万次阅读 2018-01-18 14:58:41
    相同的配置,同步调用没问题,异步调用失败,后来看了下日志,没登录被拦截了。配置拦截器后解决。  但问题是登录之后进行付款,同步通知拦截为什么就是登录状态? 另外同步通知会调用自定义页面,异步通知不会...
  • 先说下几个要点: 1. 电话拦截 这个功能大家可能都知道了,...这个就说了,在附件的代码里有。 2.拦截后提示忙音/空号/已关机/已停机 这个功能其实是要用到MMI指令,具体如何设置呼叫转移的指定可以参考这里 h
  • mybatis 分页详解、mybatis分页查询,mybatis分页拦截器使用、struts2下mybatis分页   mybatis默认是支持分页的,内部通过创建可滚动的ResultSet(ResultSet.TYPE_FORWARD_ONLY)对结果集指针进行跳转以达到分页...
  • Android通知栏Notification弹出横幅显示的解决方法:  利用Toast模拟显示Notification横幅通知,测试了多款手机,没有发现任何设备兼容性,具体实现请参考github:  ...
  • Xposed实现短信拦截

    千次阅读 2017-08-30 20:57:31
    最近在玩Xposed,然后刚好要实现个功能,收到短信的时候自动将短信的内容打印到log中,其实也算是短信拦截的一种了。然后做的时候遇见了一点坑,就写一下记录下来,当时做的时候参考了这个博客的内容。写的也很清楚...
  • 在安卓7.0之前,黑名单的短信默认是不会拦截的,为了实现黑名单短信拦截功能,需要对短信数据库表中的字段新增特殊的值,以便标记黑名单短信。以下具体说明下笔者对于MTK方案里的短信应用中拦截短彩信的实现方法。 ...
  • 技术测试地址;...由于微信限制比较严格,域名一小心就被判定是诱导分享的。...上面分享的微信域名拦截检测api,是采用微信官方接口打造,可以实时检测微信域名安全,有异常及时通知,非常稳定,准确率达100%
  • 主要介绍了Android编程实现拦截短信并屏蔽系统Notification的方法,较为详细的分析了Android短信与Notification的原理及对应的设置取消技巧,需要的朋友可以参考下
  • 部分国内ROM系统对消息栏做了拦截,因此,需要用户手动授权开启消息栏通知。 若是能够找到开启的代码,是否可以绕过拦截,默认开启呢? 本篇文章,介绍如何找到拦截点,如何去突破。至于其他的ROM系统的拦截,也...
  • 前言 我们在实际的项目开发中,肯定会有这样的需求:...可能你第一反应想到的是使用Spring MVC的拦截器HandlerInterceptor来做,此方案整体上还算优雅的,相信大部分公司的同学也都是这么来干的。那么本文就介绍一种...
  • AdBlock广告拦截插件的实现原理

    万次阅读 2015-01-13 19:43:30
    AdBlock的广告拦截实际上分为2个部分: 1、对于URL请求的拦截 这一般都是页面中DIV元素嵌入一个IFRMAE/IMAGE元素,然后加载一个广告链接或者GIF图片什么的。 这部分的规则库描述比较复杂。规则大概有几万条,即使...
  • Android广播之九——拦截短信

    千次阅读 2012-12-05 18:36:21
    2、手机收到短信以之后在通知栏上面得到一栏通知显示短信的内容的过程是这样的: (1)收到短信(2)系统发出短信有序广播,并且把电话号码和短信内容使用数据加入一起发送(3)系统自带的短信广播接收器监听到短信...
  • *由于AdBlock会在每个标签上运行,因此会自动生成有关访问历史记录和网站数据的通知。 但是,它实际上不会监视您的浏览历史记录,也不会要求您的个人信息正常工作。 ============================-版本3.3的新功能:...
  • Flutter 通知通知

    千次阅读 2019-09-10 15:23:36
    本章节叙述Flutter 通知通知功能,主要是使用Flutter与原生交互功能调用Android发送通知。 效果图 所需知识 Flutter构建通道机制Channel Android创建通知渠道NotificationChannel发送通知 实现代码 Flutter...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,791
精华内容 10,716
关键字:

不显示拦截通知