OTP(令牌)应自动从消息中读取

54

我正在开发一款Android应用程序,在该应用程序中,服务器会发送一个OTP到用户手机上,用户需要在应用程序中输入这个OTP以完成注册。我想实现的是,我的应用程序能够自动读取由服务器发送的OTP。请问如何实现?非常感谢您提供任何帮助或指导。


你可以通过编写广播接收器来读取文本消息。但是在API级别19以上,您需要制作一个默认的短信应用程序来读取消息。所以我认为这是不可能的。或者也许是可能的:请查看此链接https://dev59.com/O2Ij5IYBdhLWcg3wzINo - capt.swag
但这就是 WhatsApp 的做法。他们发送令牌/OTP/身份验证消息,然后自动读取该消息中的 OTP。 - user1903022
所以,我找到了一个链接,可以使用BroadcastReceiver读取传入的短信消息。请尝试此链接,看看是否有帮助:http://androidexample.com/Incomming_SMS_Broadcast_Receiver_-_Android_Example/index.php?view=article_discription&aid=62&aaid=87 - capt.swag
谢谢,但是这个例子只会通过显示短信内容来向我展示一个警报消息,而我需要的是自动从短信中读取服务器发送的令牌。 - user1903022
这只是 BroadcastReceiver 和 Activity 之间的通信。网上会有很多例子。 - capt.swag
显示剩余3条评论
9个回答

36

我建议您不要使用任何第三方库从短信收件箱自动获取OTP。如果您对广播接收器及其工作原理有基本的了解,这可以很容易地完成。只需尝试以下方法:

  1. 创建一个单一接口即SmsListner。
package com.wnrcorp.reba;
public interface SmsListener {
    public void messageReceived(String messageText);
}
  1. 创建单个广播接收器,即SmsReceiver
package com.wnrcorp.reba;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;

public class SmsReceiver extends BroadcastReceiver {
    private static SmsListener mListener;
    Boolean b;
    String abcd, xyz;
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle data = intent.getExtras();
        Object[] pdus = (Object[]) data.get("pdus");
        for (int i = 0; i < pdus.length; i++) {
            SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
            String sender = smsMessage.getDisplayOriginatingAddress();
            // b=sender.endsWith("WNRCRP");  //Just to fetch otp sent from WNRCRP
            String messageBody = smsMessage.getMessageBody();
            abcd = messageBody.replaceAll("[^0-9]", ""); // here abcd contains otp 
            which is in number format
            //Pass on the text to our listener.
            if (b == true) {
                mListener.messageReceived(abcd); // attach value to interface 
                object
            } else {}
        }
    }
    public static void bindListener(SmsListener listener) {
        mListener = listener;
    }
}
  1. 在Android清单文件中添加监听器,即广播接收器
<receiver android:name=".SmsReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
</receiver>

并添加权限

<uses-permission android:name="android.permission.RECEIVE_SMS"/>
  • 在收件箱中接收到OTP时,自动提取OTP并将其设置在EditText字段上的活动。
  • public class OtpVerificationActivity extends AppCompatActivity {
        EditText ed;
        TextView tv;
        String otp_generated, contactNo, id1;
        GlobalData gd = new GlobalData();
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_otp_verification);
                ed = (EditText) findViewById(R.id.otp);
                tv = (TextView) findViewById(R.id.verify_otp);
                /*This is important because this will be called every time you receive 
                 any sms */
                SmsReceiver.bindListener(new SmsListener() {
                    @Override
                    public void messageReceived(String messageText) {
                        ed.setText(messageText);
                    }
                });
                tv.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            try {
                                InputMethodManager imm =
                                    (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                                imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                            } catch (Exception e) {}
                            if (ed.getText().toString().equals(otp_generated)) {
                                Toast.makeText(OtpVerificationActivity.this, "OTP Verified 
                                    Successfully!", Toast.LENGTH_SHORT).show();           
                                }
                            });
                    }
                }
    }
    

    OtpVerificationActivity的布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_otp_verification"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.wnrcorp.reba.OtpVerificationActivity">
        <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/firstcard"
            xmlns:card_view="http://schemas.android.com/apk/res-auto"
            card_view:cardCornerRadius="10dp"
            >
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:background="@android:color/white">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="OTP Confirmation"
                    android:textSize="18sp"
                    android:textStyle="bold"
                    android:id="@+id/dialogTitle"
                    android:layout_margin="5dp"
                    android:layout_gravity="center"
                    />
                <EditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:id="@+id/otp"
                    android:layout_margin="5dp"
                    android:hint="OTP Here"
                    />
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Verify"
                    android:textSize="18sp"
                    android:id="@+id/verify_otp"
                    android:gravity="center"
                    android:padding="10dp"
                    android:layout_gravity="center"
                    android:visibility="visible"
                    android:layout_margin="5dp"
                    android:background="@color/colorPrimary"
                    android:textColor="#ffffff"
                    />
            </LinearLayout>
        </android.support.v7.widget.CardView>
    </RelativeLayout>
    

    OTP验证活动的截图,您可以在收到消息后立即获取OTP

    身份验证码,如下所示:

    输入图像描述

    1
    我们需要为此获取任何运行时权限吗? - Akshay kumar
    1
    如果您的目标是Android 6及以上版本,则需要请求运行时权限。在Android 6之前,权限会自动授予。您可以参考https://stackoverflow.com/a/40558918/7727011。 - brijexecon
    “pdus”是什么?@brijexecon - Ravi Vaniya
    不再深入细节,简单来说,它是在接收消息时使用的标志。正如您所看到的,它返回对象数组,这意味着如果您接收到具有大型正文的短信,则会在每个索引中接收到消息的部分。 - brijexecon
    5
    这个解决方案现在已经过时了。你应该使用短信验证 API。你可以在这里找到详细的指南:https://developers.google.com/identity/sms-retriever/overview - Tsiogas P.

    27
    你可以尝试使用一个简单的库像这样的。在通过gradle安装并添加权限后,在活动的onCreate方法中启动SmsVerifyCatcher。
        smsVerifyCatcher = new SmsVerifyCatcher(this, new OnSmsCatchListener<String>() {
        @Override
        public void onSmsCatch(String message) {
            String code = parseCode(message);//Parse verification code
            etCode.setText(code);//set code in edit text
            //then you can send verification code to server
        }
    });
    

    同时,重写活动生命周期方法:

      @Override
    protected void onStart() {
        super.onStart();
        smsVerifyCatcher.onStart();
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        smsVerifyCatcher.onStop();
    }
    
    /**
     * need for Android 6 real time permissions
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        smsVerifyCatcher.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
    
    
    public String parseCode(String message) {
        Pattern p = Pattern.compile("\\b\\d{4}\\b");
        Matcher m = p.matcher(message);
        String code = "";
        while (m.find()) {
            code = m.group(0);
        }
        return code;
    }
    

    可能是最好的解决方案,而且还很容易。 - TharakaNirmana
    最好的解决方案。非常感谢你。 - Christopher M.
    @angelina,这里你可以在onSmsCatch中获取完整的短信文本。因此,你需要解析消息文本以获取OTP。 - Rupam Das
    1
    但现在这已经不能使用了,因为谷歌禁用了读取短信和接收短信的功能。这在我的端上也无法工作。 - Rahul Kushwaha
    它需要短信权限,没有短信权限它将无法工作。 - Hitesh Kushwah
    显示剩余2条评论

    22

    由于Google限制了使用READ_SMS权限,因此这里提供了一种没有READ_SMS权限的解决方案。

    SMS Retriever API

    基本功能是避免使用Android关键权限READ_SMS,并使用此方法完成任务。以下是你需要的步骤:

    将OTP发送到用户号码后,请检查SMS Retriever API是否能够获取消息

    SmsRetrieverClient client = SmsRetriever.getClient(SignupSetResetPasswordActivity.this);
    Task<Void> task = client.startSmsRetriever();
    task.addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            // Android will provide message once receive. Start your broadcast receiver.
            IntentFilter filter = new IntentFilter();
            filter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);
            registerReceiver(new SmsReceiver(), filter);
        }
    });
    task.addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            // Failed to start retriever, inspect Exception for more details
        }
    });
    

    广播接收器代码

    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.os.Bundle;
    
    import com.google.android.gms.auth.api.phone.SmsRetriever;
    import com.google.android.gms.common.api.CommonStatusCodes;
    import com.google.android.gms.common.api.Status;
    
    public class SmsReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
                Bundle extras = intent.getExtras();
                Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
    
                switch (status.getStatusCode()) {
                    case CommonStatusCodes.SUCCESS:
                        // Get SMS message contents
                        String otp;
                        String msgs = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
    
                        // Extract one-time code from the message and complete verification
                        break;
                    case CommonStatusCodes.TIMEOUT:
                        // Waiting for SMS timed out (5 minutes)
                        // Handle the error ...
                        break;
                }
            }
        }
    }
    

    最后一步。将此接收器注册到您的清单中。

    <receiver android:name=".service.SmsReceiver" android:exported="true">
        <intent-filter>
            <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
        </intent-filter>
    </receiver>
    

    您的短信必须如下所示。

    <#> Your OTP code is: 6789
    QWsa8754qw2 
    

    这里的QWsa8754qw2是您自己的应用程序11个字符的哈希代码。请按照此链接

    • 长度不得超过140字节
    • 必须以前缀<#>开头
    • 必须以标识您的应用程序的11个字符哈希字符串结尾

    要导入com.google.android.gms.auth.api.phone.SmsRetriever,请不要忘记将此行添加到您的应用程序build.gradle中:

    implementation "com.google.android.gms:play-services-auth-api-phone:16.0.0"
    

    1
    这不是问题。SMS Retriever 只检查上述模式并检查哈希是否与您的应用程序匹配。如果您在开发环境中进行检查,则哈希将不同。FYI:我已尝试过发送者 ID 和手机号码。我假设发送者 ID 是类似于 TM-ABCDEF 的东西。对我来说它有效。 - Shabbir Dhangot
    2
    更新库解决了我的问题,感谢您的回复@Shabbir :) - Neo
    1
    @MustafaShaikh 要提取代码,您需要应用一些逻辑来查找消息中的代码。此 API 将检索短信并将其提供给您。我所做的是,我使用空格分割了短信,并检查了分割后字符串的第七个位置。由于我的消息是预定义的,因此它始终位于第七个位置。 - Shabbir Dhangot
    有没有办法在消息正文中隐藏哈希键? - George Thomas
    不需要隐藏它,因为没有其他应用程序可以读取你的OTP消息,这是由你的签名证书创建的哈希。所以不要担心。 - Shabbir Dhangot
    显示剩余8条评论

    5
    我实现了类似的功能。当信息到达时,我只检索六位数验证码,将其捆绑在意图中,并将其发送到需要验证该代码的活动或片段进行验证。下面的示例演示了如何获取短信。如果您的消息包含更多文本(例如问候语),请标准化它以便更好地使用。例如,“您的验证码是:84HG73”,您可以创建一个正则表达式模式,如([0-9]){2}([A-Z]){2}([0-9]){2},其中意味着两个整数,两个大写字母和两个整数。祝您好运! 从消息中丢弃所有不必要的信息后
     Intent intent = new Intent("AddedItem");
     intent.putExtra("items", code);
     LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent); 
    

    接收该消息的Fragment/Activity

    @Override
    public void onResume() {
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("AddedItem"));
        super.onResume();
    }
    
    @Override
    public void onPause() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
    }
    

    负责处理收集到的有效载荷的代码

     private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction()) {
                final String message = intent.getStringExtra("message");
                //Do whatever you want with the code here
            }
        }
    };
    

    这有点帮助。我通过使用回调函数做得更好。


    你应该重写onPause()而不是onDestroy()吧? - galdin
    这取决于你想如何使用它。如果“Fragment”或“Activity”始终处于活动状态,则将其保留在“onPause”中,但在我的情况下,我只需要它一次,因此我可以将其放在“onPause”或“onDestroy”中,因为两者都会被调用。 - Tonespy
    1
    很抱歉我没有表达清楚。调用onDestroy()方法不能保证。应根据上下文使用onStop()或onPause()方法。对吗? - galdin

    3

    抱歉回复晚了,但我觉得如果有帮助仍然想发表我的答案。这适用于6位数字OTP。

        @Override
        public void onOTPReceived(String messageBody)
        {
            Pattern pattern = Pattern.compile(SMSReceiver.OTP_REGEX);
            Matcher matcher = pattern.matcher(messageBody);
            String otp = HkpConstants.EMPTY;
            while (matcher.find())
            {
                otp = matcher.group();
            }
            checkAndSetOTP(otp);
        }
    Adding constants here
    
    public static final String OTP_REGEX = "[0-9]{1,6}";
    

    如果要监听短信,可以按照以下类:

    public class SMSReceiver extends BroadcastReceiver
    {
        public static final String SMS_BUNDLE = "pdus";
        public static final String OTP_REGEX = "[0-9]{1,6}";
        private static final String FORMAT = "format";
    
        private OnOTPSMSReceivedListener otpSMSListener;
    
        public SMSReceiver(OnOTPSMSReceivedListener listener)
        {
            otpSMSListener = listener;
        }
    
        @Override
        public void onReceive(Context context, Intent intent)
        {
            Bundle intentExtras = intent.getExtras();
            if (intentExtras != null)
            {
                Object[] sms_bundle = (Object[]) intentExtras.get(SMS_BUNDLE);
                String format = intent.getStringExtra(FORMAT);
                if (sms_bundle != null)
                {
                    otpSMSListener.onOTPSMSReceived(format, sms_bundle);
                }
                else {
                    // do nothing
                }
            }
        }
    
        @FunctionalInterface
        public interface OnOTPSMSReceivedListener
        {
            void onOTPSMSReceived(@Nullable String format, Object... smsBundle);
        }
    }
    
        @Override
        public void onOTPSMSReceived(@Nullable String format, Object... smsBundle)
        {
            for (Object aSmsBundle : smsBundle)
            {
                SmsMessage smsMessage = getIncomingMessage(format, aSmsBundle);
                String sender = smsMessage.getDisplayOriginatingAddress();
                if (sender.toLowerCase().contains(ONEMG))
                {
                    getIncomingMessage(smsMessage.getMessageBody());
                } else
                {
                    // do nothing
                }
            }
        }
    
        private SmsMessage getIncomingMessage(@Nullable String format, Object aObject)
        {
            SmsMessage currentSMS;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && format != null)
            {
                currentSMS = SmsMessage.createFromPdu((byte[]) aObject, format);
            } else
            {
                currentSMS = SmsMessage.createFromPdu((byte[]) aObject);
            }
    
            return currentSMS;
        }
    

    2

    使用短信获取器API,可以在不声明android.permission.READ_SMS的情况下读取OTP。

    1. 启动短信检索器
        private fun startSMSRetriever() {
            // Get an instance of SmsRetrieverClient, used to start listening for a matching SMS message.
            val client = SmsRetriever.getClient(this /* context */);
    
            // Starts SmsRetriever, which waits for ONE matching SMS message until timeout
            // (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
            // action SmsRetriever#SMS_RETRIEVED_ACTION.
            val task: Task<Void> = client.startSmsRetriever();
    
            // Listen for success/failure of the start Task. If in a background thread, this
            // can be made blocking using Tasks.await(task, [timeout]);
            task.addOnSuccessListener {
                Log.d("SmsRetriever", "SmsRetriever Start Success")
            }
    
            task.addOnFailureListener {
                Log.d("SmsRetriever", "SmsRetriever Start Failed")
            }
        }
    
    1. 通过广播接收消息
        public class MySMSBroadcastReceiver : BroadcastReceiver() {
    
            override fun onReceive(context: Context?, intent: Intent?) {
                if (SmsRetriever.SMS_RETRIEVED_ACTION == intent?.action && intent.extras!=null) {
                    val extras = intent.extras
                    val status = extras.get(SmsRetriever.EXTRA_STATUS) as Status
    
                    when (status.statusCode) {
                        CommonStatusCodes.SUCCESS -> {
                            // Get SMS message contents
                            val message = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
                            Log.e("Message", message);
                            // Extract one-time code from the message and complete verification
                            // by sending the code back to your server.
                        }
                        CommonStatusCodes.TIMEOUT -> {
                            // Waiting for SMS timed out (5 minutes)
                            // Handle the error ...
                        }
                    }
                }
            }
    
        }   
    
    
        /**Don't forgot to define BroadcastReceiver in AndroidManifest.xml.*/       
        <receiver android:name=".MySMSBroadcastReceiver" android:exported="true">
            <intent-filter>
                <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
            </intent-filter>
        </receiver>
    
    1. 将验证短信中的一次性代码发送到您的服务器

    请确保您的短信格式与以下格式完全相同:

    <#> Your ExampleApp code is: 123ABC78
    fBzOyyp9h6L
    
    1. Be no longer than 140 bytes
    2. Begin with the prefix <#>
    3. End with an 11-character hash string that identifies your app

      You can compute app hash with following code:

      import android.content.Context
      import android.content.ContextWrapper
      import android.content.pm.PackageManager
      import android.util.Base64
      import android.util.Log
      import java.nio.charset.StandardCharsets
      import java.security.MessageDigest
      import java.security.NoSuchAlgorithmException
      import java.util.*
      
      /**
       * This is a helper class to generate your message hash to be included in your SMS message.
       *
       * Without the correct hash, your app won't recieve the message callback. This only needs to be
       * generated once per app and stored. Then you can remove this helper class from your code.
       *
       * For More Detail: https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string
       *
       */
      public class AppSignatureHelper(private val context: Context) : ContextWrapper(context) {
      
          companion object {
              val TAG = AppSignatureHelper::class.java.simpleName;
      
              private const val HASH_TYPE = "SHA-256";
              const val NUM_HASHED_BYTES = 9;
              const val NUM_BASE64_CHAR = 11;
          }
      
          /**
           * Get all the app signatures for the current package
           * @return
           */
          public fun getAppSignatures(): ArrayList<String> {
              val appCodes = ArrayList<String>();
      
              try {
                  // Get all package signatures for the current package
                  val signatures = packageManager.getPackageInfo(
                      packageName,
                      PackageManager.GET_SIGNATURES
                  ).signatures;
      
                  // For each signature create a compatible hash
                  for (signature in signatures) {
                      val hash = hash(packageName, signature.toCharsString());
                      if (hash != null) {
                          appCodes.add(String.format("%s", hash));
                      }
                  }
              } catch (e: PackageManager.NameNotFoundException) {
                  Log.e(TAG, "Unable to find package to obtain hash.", e);
              }
              return appCodes;
          }
      
          private fun hash(packageName: String, signature: String): String? {
              val appInfo = "$packageName $signature";
              try {
                  val messageDigest = MessageDigest.getInstance(HASH_TYPE);
                  messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8));
                  var hashSignature = messageDigest.digest();
      
                  // truncated into NUM_HASHED_BYTES
                  hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
                  // encode into Base64
                  var base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING or Base64.NO_WRAP);
                  base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR);
      
                  Log.e(TAG, String.format("pkg: %s -- hash: %s", packageName, base64Hash));
                  return base64Hash;
              } catch (e: NoSuchAlgorithmException) {
                  Log.e(TAG, "hash:NoSuchAlgorithm", e);
              }
              return null;
          }
      }       
      

    所需的Gradle版本:

    implementation "com.google.android.gms:play-services-auth-api-phone:16.0.0"
    

    References:
    https://developers.google.com/identity/sms-retriever/overview
    https://developers.google.com/identity/sms-retriever/request
    https://developers.google.com/identity/sms-retriever/verify


    0

    0

    虽然有点晚了,但为了让其他人更容易理解,这里是我之前写过的解决方案。 使用这个库链接。你不需要去搞什么。 在添加依赖后,只需使用这个方法即可。

    OtpFetcher.getInstance().verifyOtpByMatchingString(this, "OTP", 21000, object : OtpListener {
                override fun onReceived(messageItem: MessageItem) {
                    Toast.makeText(this@MainActivity, "" + messageItem, Toast.LENGTH_SHORT).show()
                }
    
                override fun onTimeOut() {
                    Toast.makeText(this@MainActivity, "TimeOut", Toast.LENGTH_SHORT).show()
    
                }
            })
    

    您需要传递上下文和消息的搜索字符串,例如:

    如果您期望在消息中收到OTP,请传递“OTP”和超时时间以指定您希望监听OTP的时间长度。这样,您将在OnRecieved回调中以简单格式获取您的消息。


    这个不起作用,已经测试了数字和字符串匹配器。 - Mubashir Murtaza
    你能分享一下代码吗?或者你遇到了什么错误?你在客户端添加了权限吗? - Intsab Haider
    我正在从Firebase接收消息,即使Firebase自己的函数也没有读取我的消息,所以我必须进行自定义工作,现在我正在使用另一个库,它正在工作。 - Mubashir Murtaza

    -2
    **activity_main.xml**
    
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.mukundwn.broadcastreceiver.MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </android.support.constraint.ConstraintLayout>
    
    
    
    **MainActivity.java**
    import android.content.BroadcastReceiver;
    import android.content.IntentFilter;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity {
    
        private BroadcastReceiver broadcastReceiver;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            broadcastReceiver =new MyBroadcastReceiver();
        }
    
    @Override
        protected void onStart()
    {
        super.onStart();
        IntentFilter intentFilter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
        registerReceiver(broadcastReceiver,intentFilter);
    }
    @Override
        protected void onStop()
    {
        super.onStop();
        unregisterReceiver(broadcastReceiver);
    }
    
    }
    
    
    **MyBroadcastReceiver.java**
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.widget.Toast;
    
    /**
     * Created by mukundwn on 12/02/18.
     */
    
    public class MyBroadcastReceiver extends BroadcastReceiver {
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"hello received an sms",Toast.LENGTH_SHORT).show();
        }
    }
    
    
    **Manifest.xml**
    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.mukundwn.broadcastreceiver">
    
        <uses-permission android:name="android.permission.RECEIVE_SMS"/>
        <uses-permission android:name="android.permission.READ_SMS"></uses-permission>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            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=".MyBroadcastReceiver">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVE"></action>
            </intent-filter>
            </receiver>
        </application>
    
    </manifest>
    

    虽然这段代码片段可能解决了问题,但包括解释有助于提高您的回答质量。请记住,您正在为未来的读者回答问题,而这些人可能不知道您提出代码建议的原因。 - Stefan Crain

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接