android短信上送验证的实现及问题

xiaoxiao2021-02-28  116

短信验证码作为一种验证方式,已经普遍存在于各种App中,通常由于网络、手机设置等各种原因,用户不能正常接收到App下发给用户的短信验证码,所以需要通过用户上送短信的方式来完成验证。最近在实现这个功能时遇到了有意思的事情,顺便研究下并记录下来。

1. 功能描述:App中提供按钮,点击时跳到短信编辑页面,将之前从服务器获取的目标号码和发送内容填充在该页面。

2. 功能实现:通过Intent跳转方式实现

1)使用Activity.startActivity()

/** * 跳转至发送短信编辑界面,Activity跳转方式 * @param smsUpNumber * @param smsContent */ private void sendSMS(String smsUpNumber,String smsContent) { Log.d("[RLIGHT]","send SMS, number " + smsUpNumber + " content " + smsContent); Uri smsToUri = Uri.parse("smsto:" + smsUpNumber); Intent intent = new Intent(Intent.ACTION_SENDTO, smsToUri); intent.putExtra("sms_body", smsContent); startActivity(intent); }2)  使用Context.startActivity()

/** * 跳转至发送短信编辑界面,Context跳转方式 * @param smsUpNumber * @param smsContent */ private void sendSMS1(String smsUpNumber,String smsContent) { Log.d("[RLIGHT]","send SMS 1, number " + smsUpNumber + " content " + smsContent); Uri smsToUri = Uri.parse("smsto:" + smsUpNumber); Intent intent = new Intent(Intent.ACTION_SENDTO, smsToUri); intent.putExtra("sms_body", smsContent); getApplicationContext().startActivity(intent); }       就在使用Context的startActivity时,遇到了些有意思的问题,如下:

       首先,在一台6.0的测试机上闪退,报错如下:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.rlight.smstest, PID: 12800 android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?                                                                                 at android.app.ContextImpl.startActivity(ContextImpl.java:757)                                                                                 at android.app.ContextImpl.startActivity(ContextImpl.java:737)                                                                                 at android.content.ContextWrapper.startActivity(ContextWrapper.java:331)                                                                                 at com.example.rlight.smstest.MainActivity.sendSMS1(MainActivity.java:82)                                                                                 at com.example.rlight.smstest.MainActivity.access$200(MainActivity.java:13)                                                                                 at com.example.rlight.smstest.MainActivity$2.onClick(MainActivity.java:36)                                                                              

        根据报错提示,可以知道在Context中使用startActivit需要设置FLAG_ACTIVITY_NEW_TASK,查看API23的源码,发现也是说明了这一点的,如下:

/** * Launch a new activity. You will not receive any information about when * the activity exits. * * <p>Note that if this method is being called from outside of an * {@link android.app.Activity} Context, then the Intent must include * the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag. This is because, * without being started from an existing Activity, there is no existing * task in which to place the new activity and thus it needs to be placed * in its own separate task. * * <p>This method throws {@link ActivityNotFoundException} * if there was no Activity found to run the given Intent. * * @param intent The description of the activity to start. * @param options Additional options for how the Activity should be started. * May be null if there are no options. See {@link android.app.ActivityOptions} * for how to build the Bundle supplied here; there are no supported definitions * for building it manually. * * @throws ActivityNotFoundException * * @see #startActivity(Intent) * @see PackageManager#resolveActivity */ public abstract void startActivity(Intent intent, @Nullable Bundle options);           简单的说,即如果是从一个外部的Context调用startActivity方法,对应的Intent必须包含FLAG_ACTIVITY_NEW_TASK启动标识。这是因为如果一个新Activity不是通过已经存在的Activity来启动的,则不存在task用于存放该新Activity,因此需要在自己的独立task中存放。因此解决这个问题,只需要添加如下代码:

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK ); // 使用Context的startActivity需要如此设置

          调用Activity中的startActivity则可以不用添加该标识,因为新Activity默认存在在调用Activity的task中,在对应源码中也说明了这一点,如下:

/** * Launch a new activity. You will not receive any information about when * the activity exits. This implementation overrides the base version, * providing information about * the activity performing the launch. Because of this additional * information, the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag is not * required; if not specified, the new activity will be added to the * task of the caller. * * <p>This method throws {@link android.content.ActivityNotFoundException} * if there was no Activity found to run the given Intent. * * @param intent The intent to start. * @param options Additional options for how the Activity should be started. * See {@link android.content.Context#startActivity(Intent, Bundle) * Context.startActivity(Intent, Bundle)} for more details. * * @throws android.content.ActivityNotFoundException * * @see {@link #startActivity(Intent)} * @see #startActivityForResult */ @Override public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); } }         然而,到这里还没有结束,发现了两个奇怪的地方,如下:

        第一,7.0+的设备上不存在这个问题,即使用Context的startActivity时,Intent不需要添加FLAG_ACTIVITY_NEW_TASK标识,查看对应API24、API25源码注释,注释中明确注明需要该标识,可是实际运行并不需要,这个问题暂时没找到合理的解释。         第二,为了实现每次调用发送不同验证码的效果,在点击并跳往短信编辑页面时,smsContent传入的内容每次都不同。当在短信界面按返回键返回至App中,再次调用sendSMS1方法跳往短信界面,编辑的内容更新了,然而,如果不是返回键,而是通过home键切换后台的方式切回App,再调用sendSMS1方法跳往短信界面,神奇的发现短信界面保留的是旧的内容而没更新。经过研究发现,这种问题可以通过增加Intent的Flag标识FLAG_ACTIVITY_NO_HISTORY来解决。如下:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);        该标识的解释如下:

/** * If set, the new activity is not kept in the history stack. As soon as * the user navigates away from it, the activity is finished. This may also * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory * noHistory} attribute. * * <p>If set, {@link android.app.Activity#onActivityResult onActivityResult()} * is never invoked when the current activity starts a new activity which * sets a result and finishes. */ public static final int FLAG_ACTIVITY_NO_HISTORY = 0x40000000;         Intent中各标识的解释用法可参照:http://blog.csdn.net/guiwang2008/article/details/21184383

转载请注明原文地址: https://www.6miu.com/read-78887.html

最新回复(0)