微信支付注意事项--Android版

微信支付有一些需要注意的细节,官方文档上并没有做出详细的说明,需要开发者自己探索;这里结合自己的经验,把需要注意的事项尽可能多的列出来,避免再次踩坑。

1–要测试微信支付,必须要打包apk,而且打包时用的keystore,要和微信开放平台上的keystore要一致;否则微信在校验的时候就不会通过,无法调出支付界面。

2–微信支付返回的结果码,会在微信官方给的WXPayEntryActivity中得到。
WXPayEntryActivity的路径微信官方有严格的要求,要依照官方的要求,将WXPayEntryActivity放到对应的包下,才会正确的回调。
官方要求的路径:你的包名.wxapi.WXPayEntryActivity
也就是说,要在包名路径下创建wxapi包,将WXPayEntryActivity放在这个wxapi下。这样才会得到正确的回调。

3–因为WXPayEntryActivity是被微信app来调用的,所以:
AndroidManifest.xml中WXPayEntryActivity的android:exported=”true”
exported值的作用在于:当前Activity是否可以被另一个Application的组件启动:true允许被启动;false不允许被启动。
所以,如果这个值没有被设置成true,WXPayEntryActivity是不允许被其他app调用的,微信也就无法将结果码返回。

4–关于WXPayEntryActivity的返回结果码的获得和传出。
支付结果返回码errCode在onResp中返回,但是传出却有不少问题。
因为WXPayEntryActivity是被其他app(微信)调用的,所以其对应的context,并不是自己程序中的context。
也就是说,如果通过WXPayEntryActivity来获取本程序的application或者SharedPreferences,并将一些结果码存到application或SharedPreferences中,用传统的方法是不可取的。得到的application和SharedPreferences都将是null。
4.1–以下是在WXPayEntryActivity中的测试代码:

//这里application打印出来的结果为null
MyApplication   application = (MyApplication)WXPayEntryActivity.this.getApplication();
    LogUtil.d("tag", "application == "+application );
//SharedPreferencesUtil是自己写的一个获取SharedPreferences的工具类
//传自己程序的activity可正常获得SharedPreferences并修改或查询里面的数据,但传入WXPayEntryActivity后,打印值为null
SharedPreferencesUtil   spUtil = new SharedPreferencesUtil(WXPayEntryActivity.this);
LogUtil.d("tag", "spUtil == "+spUtil );

4.2–传统方法不行,那就换个方法——获取指定app的Context:

        try {
        //PACKNAME是指定app的包名,比如com.myapp.app,你只要知道包名,就能获得这个包的Context 
            Context mContext = WXPayEntryActivity.this.createPackageContext(PACKNAME, Context.CONTEXT_IGNORE_SECURITY);
            String packName = mContext.getPackageName();
            LogUtil.d("tag", "mContext == "+mContext );
            LogUtil.d("tag", "packName == "+packName );
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

原本以为这样就可以成功获得自己程序的Context,这样就可以很方便的保存或传出支付结果码,然而打印结果显示,mContext 和 packName 都 == null。
这里没有弄明白为什么会是null,但总之这条路是不通的。
4.3–此路不通,再换一条路:通过activity的intent进行通信。
在拿到支付结果码时,做界面的跳转,携带intent将结果码带出去,WXPayEntryActivity中的代码如下:

Intent intent = new Intent(this, WaitPayListActivity.class);
intent.putExtra("errCode", "0");
startActivity(intent);

在WaitPayListActivity获取errCode

String errCode = getIntent().getStringExtra("errCode");
LogUtil.d("tag", "errCode == "+errCode);

得到的结果是,errCode == null
虽然界面跳转了,但是intent并没有穿过来。
判断应该是因为WXPayEntryActivity是其他app中的,与自己的activity不在同一个进程中,普通的intent不能进行跨进程通信。
4.4–activity的intent进行跨进程通信
因为WaitPayListActivity用来接受支付结果码,那么WaitPayListActivity的android:exported=”true”以让其他进程调用,把WaitPayListActivity共享给其他应用。
代码如下:

        <activity
            android:name=".activity.WaitPayListActivity"
            android:exported="true"
            android:screenOrientation="portrait"
android:theme="@android:style/Theme.Holo.Light.NoActionBar" >
            <intent-filter>
                <action android:name="com.myapp.ACTION"/>
                <data android:scheme="info"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

1)action 是指定的动作,可以自定义,只要知道action的name,其他应用就可以找到这个activity
2)data 的 android:scheme 是intent的通信协议,只要采用的相同的协议,就可以携带数据过来。
3)category 是intent的类型
关于activity中的跨进程访问原理和细节,可参考如下博客:
http://blog.csdn.net/dj0379/article/details/50852659
http://blog.csdn.net/smile_yingying/article/details/39351981

将WaitPayListActivity共享后,WXPayEntryActivity便可以通过隐式intent来跳转到WaitPayListActivity。

//URI定义了通信协议,要符合WaitPayListActivity的<data android:scheme="info"/>
//"info://"是协议格式,类似"http://",后面的wxpay是传过去的值
Uri rui = Uri.parse("info://wxpay");
//通过Action和URI调用其他进程中的Activity,并传递数据
Intent intent = new Intent(ACTION, rui);
intent.putExtra("errCode", "0");
WXPayEntryActivity.this.startActivity(intent);

在WaitPayListActivity中接收intent。

        if (getIntent().getData() != null) {//getData方法获取的是传过来的URI
            LogUtil.d("tag", "getIntent().getData() != null");
            //要对URI做非空判断,否则报空指针;有URI,才会有getExtras的数据
            String errCode = getIntent().getExtras().getString("errCode");
            LogUtil.d("tag", "errCode == "+errCode);
        }else {
            LogUtil.d("tag", "getIntent().getData() == null");
        }

得到的结果是:getIntent().getData() == null
也就是说,intent中的Uri都没有传过来,更不要说里面携带的数据了。
但是界面执行了正确的跳转,跳到了WaitPayListActivity。
Uri协议格式并没有不一致,但没有数据过来,这个原因没有弄清楚,不知道是不是实现了微信接口的原因。(IWXAPIEventHandler)

以上尝试的几种办法都没有将errCode传出来,当然,还可以尝试用ContentProvider,Service或广播。
在这里,我通过对不同结果码跳转到不同界面的方法,来对结果码做判断,完成自己所需要的效果。

注:事后发现,errCode传不出来,是因为在WXPayEntryActivity中,api.handleIntent(getIntent(), this)方法执行后,会直接跳转到onResp()方法,而不是继续执行紧跟api.handleIntent()之后的代码;所以,application的初始化在api.handleIntent()之前执行,就可以得到一个正确的application,而不再是null,此时解决了传不出errCode值的问题。补充于2017.05.23

        //初始化IWXAPI
        api = WXAPIFactory.createWXAPI(this, UpostConstants.WECHAT_APP_ID);
        //此代码将Intent传给后面的onReq、onResp方法,再执行此代码之后的代码
        api.handleIntent(getIntent(), this);

5–在WXPayEntryActivity的onCreate和onNewIntent方法中需要调用IWXAPI.handleIntent(intent, context);否则调不起微信。

public class WXPayEntryActivity extends AppCompatActivity implements IWXAPIEventHandler {

    private IWXAPI api;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ac_wxpay_entry);
        api = WXAPIFactory.createWXAPI(this, WxPayUtils.APP_ID);
        api.handleIntent(getIntent(), this);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }

    @Override
    public void onReq(BaseReq req) {
        //...
    }

    @Override
    public void onResp(BaseResp resp) {
        //这里处理返回结果码resp.errCode
    }
}

6–最后但不是不重要的注意点:在执行跳转到微信支付界方法【api.sendReq(req)】前,要先注册应用到微信。否则调用不成功。

        // 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
        api.sendReq(req);

可以在执行跳转的activity被创建时注册,也可以在其他地方注册,总是是要在sendReq方法前要进行注册。
微信官方的Demo,是通过BroadcastReceiver来注册的,可以参考官方的,以下是代码:

/**将App注册到微信*/
public class AppWXRegister extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        IWXAPI api = WXAPIFactory.createWXAPI(context, null);
        // 将该App注册到微信
        api.registerApp(UpostConstants.WECHAT_APP_ID);
    }

}

清单配置文件中注册这个广播:

        <receiver android:name=".receiver.AppWXRegister" >
            <intent-filter>
                <action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
            </intent-filter>
        </receiver>

以上是微信支付中,很可能会碰到的问题,总结出来,让自己和其他人都少走弯路,少踩坑。

PS:如果不需要显示WXPayEntryActivity,可以将主题设置成
android:theme=”@android:style/Theme.NoDisplay”
以及在拿到结果码就立即跳转界面,并finish掉WXPayEntryActivity。
此外,WXPayEntryActivity还有一个小惊喜,那就是如果在WXPayEntryActivity中碰到了空指针异常,WXPayEntryActivity界面就将一直停留,并不像普通activity一样立即消失。
所以如果WXPayEntryActivity突然卡住不动了,快去看看是否有空指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值