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

短信验证码作为一种验证方式,已经普遍存在于各种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


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值