分享一下个人免签的实现方法,其实这个很简单,其实就是对 Android Notification 通知消息进行的监听,根据消息内容的金额来进行支付判断。举个例子

  1. 微信生成收款二维码,保存下来让其它人去扫码。现在扫码付款 0.01 元。然后手机通知栏弹出消息,标题:微信支付,内容:微信支付收款 0.01 元。
  2. 你开发的 App 通过获取通知栏消息,通过获取包名判断是微信支付或者还是支付宝支付,然后正则获取金额,将这些金额回调给你的服务端进行处理。
  3. 服务端通过金额+支付类型判断来判断这笔订单是否支付成功。

支付二维码的生成方式有两种

  1. 你需要自己生成N个金额的二维码然后对应你的支付金额,譬如1元的,你待生成0.9-1元,10个二维码。为什么是10个呢?因为有可能多个支付,如果金额重复了,就无法判断是否成功了。
  2. 使用 VirtualXposed 通过 Hook 自动生成二维码,添加备注等这个就解决金额重复的问题了。但是不支持新版本的支付宝和微信,这个东西特别容易封号,而且对手机的配置也要求的相当高,最低3G运行起来还凑合。所以建议安全还是用第一种方法。

实现第一步获取权限 NotificationListenerService 监听权限,获取权限后才能监听到通知栏消息。先判断是否获取权限,假如没有权限就前往授权。代码如下:

String string = Settings.Secure.getString(getContentResolver(),"enabled_notification_listeners");
if(!string.contains(com.weiduyun.WeiYunPayNotificationService.class.getName())){
    new Builder(this)
        .setTitle((CharSequence) "温馨提示")
        .setMessage((CharSequence) "未授权读取通知栏权限,请先前往授权")
        .setPositiveButton((CharSequence) "前往授权",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        MainActivity.this.startActivityForResult(
                                new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"),
                                200
                        );
                    }
                }).create().show();
}else{
    startService(new Intent(this, com.weiduyun.WeiYunPayMonitorService.class));
}

其中 WeiYunPayNotificationService 是你的自己写的监听服务。当然你也需要在 AndroidManifest.xml 中注册服务,没有权限就前往授权。否则的话,启动 WeiYunPayMonitorService 服务,这个自己写自己的逻辑就行。这里有个坑,当你的 App 重启之后你会发现 NotificationListenerService 无法启动。这里你就需要写代码来检测,如果为启动,就重启服务。代码判断如下:

    
    private void runingService() {
        Log.d(TAG, "service check");
        ComponentName component = new ComponentName(this, com.weiduyun.WeiYunPayNotificationService.class);
        boolean runing = false;
        List<ActivityManager.RunningServiceInfo> runningServiceInfos = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)).getRunningServices(Integer.MAX_VALUE);
        if(runningServiceInfos == null) {
            Log.d(TAG, "Runing Service Is Null");
            return;
        }
        for (ActivityManager.RunningServiceInfo runningServiceInfo : runningServiceInfos) {
            Log.d(TAG, runningServiceInfo.service.toShortString());
            if( runningServiceInfo.service.equals(component) ) {
                if (runningServiceInfo.pid == Process.myPid() ) {
                    runing = true;
                }
            }
        }
        if( runing )
        {
            return;
        }
        toggleNotificationListenerService();
    }

    /**
     * 重新启动监听服务
     */
    private void toggleNotificationListenerService() {
        ComponentName thisComponent = new ComponentName(this,  WeiYunPayNotificationService.class);
        PackageManager pm = getPackageManager();
        pm.setComponentEnabledSetting(thisComponent, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
        pm.setComponentEnabledSetting(thisComponent, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
    }

这个方法我就写在了 WeiYunPayMonitorService 中,而且在 WeiYunPayMonitorService 中我自定义了状态通知栏,显示在运行的服务,以及重启服务。

今天就说到这里,明天继续……