axios拦截器_在Android上拦截传入的短信

axios拦截器

axios拦截器

上周,我谈到了使用SMS激活您的应用程序,这是验证用户帐户的一种非常有效的方法。 不过,我忽略了两件事。 其中之一是能够自动捕获传入的SMS。 这仅在Android上可行,但对用户来说很酷,因为它省去了键入激活文本的麻烦。

广播接收器

为了获取传入的SMS,我们需要一个广播接收器,它是一个独立的Android类,可以接收特定的事件类型。 这常常使有时会从广播接收器派生impl类的开发人员感到困惑...这是一个错误...

诀窍是您可以将任何本机Android类放到native/android目录中。 它将与其余的本机代码一起编译,并且“正常工作”。 所以我把这个类放在native/android/com/codename1/sms/intercept

package com.codename1.sms.intercept;

import android.content.*;
import android.os.Bundle;
import android.telephony.*;
import com.codename1.io.Log;

public class SMSListener extends BroadcastReceiver {

    @Override
    public void onReceive(Context cntxt, Intent intent) {
        // based on code from https://stackoverflow.com/questions/39526138/broadcast-receiver-for-receive-sms-is-not-working-when-declared-in-manifeststat
        if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
            Bundle bundle = intent.getExtras();
            SmsMessage[] msgs = null;
            if (bundle != null){
                try{
                    Object[] pdus = (Object[]) bundle.get("pdus");
                    msgs = new SmsMessage[pdus.length];
                    for(int i=0; i<msgs.length; i++){
                        msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
                        String msgBody = msgs[i].getMessageBody();
                        SMSCallback.smsReceived(msgBody);
                    }
                } catch(Exception e) {
                    Log.e(e);
                    SMSCallback.smsReceiveError(e);
                }
            }
        }
    }
}

上面的代码是非常标准的原生Android代码,它只是一个回调,其中的大多数逻辑类似于此stackoverflow问题中提到的原生Android代码。

但是,我们还有更多要做的事情。 为了以本地方式实现此功能,我们需要按照该问题中的说明,在manifest.xml文件中注册权限和接收者。 这是他们的本机清单的样子:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.bulsy.smstalk1">
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="com.bulsy.smstalk1.SmsListener"
               android:enabled="true"
               android:permission="android.permission.BROADCAST_SMS"
               android:exported="true">
            <intent-filter android:priority="2147483647">//this doesnt work
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

我们只需要广播许可XML和许可XML。 两者都可以通过构建提示来实现。 前者很容易:

android.xpermissions=<uses-permission android:name="android.permission.RECEIVE_SMS" />

后者并不难,请注意,为了方便起见,我将多行代码并成一行:

android.xapplication=<receiver android:name="com.codename1.sms.intercept.SMSListener"  android:enabled="true" android:permission="android.permission.BROADCAST_SMS"  android:exported="true">                    <intent-filter android:priority="2147483647"><category android:name="android.intent.category.DEFAULT" />        <action android:name="android.provider.Telephony.SMS_RECEIVED" />                 </intent-filter>             </receiver>

在这里,它的格式很好:

<receiver android:name="com.codename1.sms.intercept.SMSListener"
              android:enabled="true"
              android:permission="android.permission.BROADCAST_SMS"
              android:exported="true">
                   <intent-filter android:priority="2147483647">
                          <category android:name="android.intent.category.DEFAULT" />
                          <action android:name="android.provider.Telephony.SMS_RECEIVED" />
                   </intent-filter>
</receiver>

听力与权限

您会注意到,这些不包括您期望的类似这样的实际绑定或权限提示。 为此,我们需要一个本机接口。

堆栈溢出中的本机样本在活动中绑定了侦听器,但在这里我们希望应用程序代码决定何时应绑定侦听器:

public interface NativeSMSInterceptor extends NativeInterface {
    public void bindSMSListener();
    public void unbindSMSListener();
}

这很容易!

注意,对于所有其他操作系统, isSupported()返回false,因此我们不需要询问这是否是“ Android”,我们可以使用isSupported()

实现也很容易:

package com.codename1.sms.intercept;

import android.Manifest;
import android.content.IntentFilter;
import com.codename1.impl.android.AndroidNativeUtil;

public class NativeSMSInterceptorImpl {
    private SMSListener smsListener;
    public void bindSMSListener() {
        if(AndroidNativeUtil.checkForPermission(Manifest.permission.RECEIVE_SMS, "We can automatically enter the SMS code for you")) { (1)
            smsListener = new SMSListener();
            IntentFilter filter = new IntentFilter();
            filter.addAction("android.provider.Telephony.SMS_RECEIVED");
            AndroidNativeUtil.getActivity().registerReceiver(smsListener, filter); (2)
        }
    }

    public void unbindSMSListener() {
        AndroidNativeUtil.getActivity().unregisterReceiver(smsListener);
    }

    public boolean isSupported() {
        return true;
    }
}
1个 这将触发Android 6及更高版本上的权限提示。 即使以XML声明了权限,对于6岁以上的用户来说还是不够的。 请注意,即使您在Android 6上运行,您仍需要声明XML权限!
2 在这里,我们实际上绑定了侦听器,这使我们可以获取一条短信,而不会在收到的每条短信中进行监听

回呼

到现在为止,该代码还不太实用,因此请对其进行抽象。 但是首先,我们需要实现上面的代码向其中发送SMS和错误的回调类:

package com.codename1.sms.intercept; (1)

import com.codename1.util.FailureCallback;
import com.codename1.util.SuccessCallback;
import static com.codename1.ui.CN.*;

/**
 * This is an internal class, it's package protect to hide that
 */
class SMSCallback {
    static SuccessCallback<String> onSuccess;
    static FailureCallback onFail;

    public static void smsReceived(String sms) {
        if(onSuccess != null) {
            SuccessCallback<String> s = onSuccess;
            onSuccess = null;
            onFail = null;
            SMSInterceptor.unbindListener();
            callSerially(() -> s.onSucess(sms)); (2)
        }
    }

    public static void smsReceiveError(Exception err) {
        if(onFail != null) {
            FailureCallback f = onFail;
            onFail = null;
            SMSInterceptor.unbindListener();
            onSuccess = null;
            callSerially(() -> f.onError(null, err, 1, err.toString()));
        } else {
            if(onSuccess != null) {
                SMSInterceptor.unbindListener();
                onSuccess = null;
            }
        }
    }
}
1个 请注意,程序包与本机代码和其他类相同。 这允许回调类受到包保护,因此不会通过API公开(该类没有public修饰符)
2 我们按顺序将回调包装在调用中,以匹配默认情况下使用EDT的Codename One约定。 该调用可能会到达Android本机线程,因此有必要对其进行规范化,并且不要将Android本机线程公开给用户代码。

一个简单的API

难题的最后一部分是一个简单的API,该API可以将整个内容包装起来,并且还隐藏了特定于Android的事实。 在上一期文章中,我们将介绍完整的API,但是现在这是隐藏本机接口的用户级API。 使用这样的类通常是一种好的做法,因为它使我们可以灵活地使用实际的基础本机接口。

package com.codename1.sms.intercept;

import com.codename1.system.NativeLookup;
import com.codename1.util.FailureCallback;
import com.codename1.util.SuccessCallback;

/**
 * This is a high level abstraction of the native classes and callbacks rolled into one.
 */
public class SMSInterceptor {
    private static NativeSMSInterceptor nativeImpl;

    private static NativeSMSInterceptor get() {
        if(nativeImpl == null) {
            nativeImpl = NativeLookup.create(NativeSMSInterceptor.class);
            if(!nativeImpl.isSupported()) {
                nativeImpl = null;
            }
        }
        return nativeImpl;
    }

    public static boolean isSupported() {
        return get() != null;
    }

    public static void grabNextSMS(SuccessCallback<String> onSuccess) {
        SMSCallback.onSuccess = onSuccess;
        get().bindSMSListener();
    }

    static void unbindListener() {
        get().unbindSMSListener();
    }
}

下次

下次,我将结合用户体验,将所有内容打包到易于使用的cn1lib中。

就本机接口的使用而言,我在此处涉及到的一些内容可能有些“冗长”,因此,如果不清楚,只需在注释中提出即可。

翻译自: https://www.javacodegeeks.com/2017/09/intercept-incoming-sms-android.html

axios拦截器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值