I have encountered many problems in paying this for H5 at work, so I want to record it, maybe I will forget it in the future. For those that have not been connected, I can also take a look to avoid many problems.
background
Due to the need for more flexible operation scenarios, third-party (wechat, Alipay) H5 payment needs to be connected within the APP
Basic information Document
WeChat h5 pay for development and common problem: pay.weixin.qq.com/wiki/doc/ap…
practice
The basic access method is not explained too much. The following is a brief description of the problems encountered in the process of using H5 payment from the dimension of the project and the treatment methods.
Constellation card game
Summary:
Constellation game is a card type gold draw small game, the user by choosing the corresponding card to draw more than the equivalent amount of gold;
Basic process:
Key logic and processing methods
First, constellation card small game adjust wechat H5 payment
// Open wechat Pay
let payParams = JSON.parse(ret.data.payParams)
let openWxUrl = payParams.payUrl + "&redirect_url=" + encodeURIComponent(redirectUrl)
let hideFrame = document.createElement('iframe')
hideFrame.setAttribute('src', openWxUrl);
hideFrame.setAttribute('sandbox'.'allow-scripts allow-top-navigation allow-same-origin')
document.body.appendChild(hideFrame)
/* Iframe onload is more elegant, because the user load iframe time is affected by the network environment, Direct 2 s after removing the uncontrolled setTimeout (function () {hideFrame. ParentNode. RemoveChild (hideFrame); }, 2000); * /
hideFrame.onload = function(){
// Other logic
setTimeout(function() {
hideFrame.parentNode.removeChild(hideFrame);
}, 100);
}
Copy the code
The above code, there are several logical processing, corresponding, through the following several questions to explain;
- Why load the payUrl as an iframe?
It is determined by the interaction of the Constellation mini game. Because users need to draw prizes on the current page after payment, it can also solve the referer verification problem of wechat H5 payment for payUrl loading through the form of IFrame processing.
- Why does iframe set sandbox? Why set setTimeout to remove iframe?
- When ios13 was released, ios had a problem, wechat H5 payment did not adjust successfully;
- The same problem occurred after a certain version of The App of Android. For that version of the app, the Android SDK version packaged with the app was updated
The corresponding exception log is as follows
message:Uncaught SecurityError: Failed to set the 'href' property on 'Location': The current window does not have permission to navigate the target frame to 'weixin://wap/pay? prepayid%3Dwx241530497040689dd1394a4f1296524900&package=3510274145&noncestr=1563953450&sign=7867a2dd7feb974db9285725cb28 22d0'. The error code seen from log is not the code of the business itself, but the "top.location.href" exception in the payment page after the payUrl is loaded. The key code is as followsCopy the code
Key logic codes of payUrl returned by wechat H5 payment after pre-ordering are as follows:
//payUrl
var is_postmsg="";
if(is_postmsg=="1")
{
parent.postMessage(JSON.stringify({
action : "send_deeplink".data : {
deeplink : "weixin://wap/pay? prepayid%3Dwx28141344091494d0c83d3c3cd472e50000&package=3738825662&noncestr=1609136025&sign=02d138bef13beb9222479014a4a4 ea85"}}),"");
}
else
{
var url="weixin://wap/pay? prepayid%3Dwx28141344091494d0c83d3c3cd472e50000&package=3738825662&noncestr=1609136025&sign=02d138bef13beb9222479014a4a4 ea85";
var redirect_url="https://ulink.com/ulink/lucky/index.html";
top.location.href=url;
if(redirect_url)
{
setTimeout(
function(){
top.location.href=redirect_url;
},
5000
);
}
else
{
setTimeout(
function(){
window.history.back();
},
5000); }}Copy the code
From the above code block, you can see the logic of payUrl to call wechat
-
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
If there is a redirect_URL, a timer will be set and redirected to the redirect_URL after 5 seconds — this is why the constellation games need to add a remove iframe logic.
After the app is packaged with the new Android SDK, the kernel version of WebView is upgraded and the corresponding content security policy (CSP) is adjusted (the default Settings are adjusted), which prevents payUrl from directly accessing the parent page API through the way of TOP. This problem is solved by setting the sandbox property to iframe:
/* sandbox allow-forms allow-scripts Run the execution script allow-same-origin to allow same-domain requests such as Ajax,storage allow-top-navigation Allow-popups Allows an iframe to pop new Windows, for example,window.open,target= "_blank" allow-pointer-lock The mouse can be locked in iframe, mainly related to mouse locking */
hideFrame.setAttribute('sandbox'.'allow-scripts allow-top-navigation allow-same-origin')
Copy the code
3. RedirectUrl is a callback address. How does wechat jump back to the specified address? RedirectUrl Why is the ULink address configured?
The logic of wechat processing redirectUrl is as follows:
if(redirect_url)
{
setTimeout(
function(){
top.location.href=redirect_url;
},
5000);
}
else
{
setTimeout(
function(){
window.history.back();
},
5000); } redirectUrl Why is the ulink address configured?Copy the code
After the wechat Payment is completed, android will return to the wechat Payment app by clicking the “Finish” button on the successful payment page. Ios will not do this operation by clicking “Finish”, and safari will open redirectUrl when redirectUrl is configured. RedirectUrl also has domain name authentication.
The ulink address is configured to solve the processing mode of ios returning to app after payment is completed.
Note: There is also a case that ios cannot directly return to the APP, but opens the ulink page through Safari. In this case, after checking with colleagues on the client, the user did not download the apple-app-site-Association file when installing the app.
App Recharge (embedded, external)
Summary:
The embedded H5 recharge page provides a page convenient for users to recharge, and supports wechat Pay, Alipay payment, corresponding to the recharge in the APP;
Basic logic:
Similar to the constellation card game, the difference is that the lottery has become the user to pay to complete the state of the polling;
I. Wechat H5 payment
After avoiding the problems in the constellation mini game, there are no other problems for the time being (this is a new problem in the reload window of the sub-app); Interaction sequence diagram after loading payUrl (unofficial) :
Two, Alipay H5 payment (Alipay H5 payment has two ways: 1. Pure H5 page payment; 2. H5 activates Alipay app payment), the following is the process of H5 activates Alipay app payment
So alipay h5, instead of payUrl, returns a formDomString;
Interaction sequence diagram after payForm submission (unofficial) :
<! -- Alipay H5 Payment, <form name= "punchout_form "method= "post" action=\"https://openapi.alipay.com/gateway.do?charset=UTF-8&method=alipay.trade.wap.pay&sign=HfcRgFeT%2FSVj1soSQrBQYCV% 2BaoQzrBVupczUmmjM0sQ2FqXlFHMqOti4EexmhSh3Ap%2FRAAG8MXlo%2FTbzVquR59bXe3deuTXc30S5cgsV9l00jaKPOKXdSfJah2r%2FR5onafKys9ca XLaaQmVwtrSrWr5hMFz%2FmtfZvZWwch%2FFvJuVS0wlGT128GBG0KSiUue0g2Bs%2BVg%2B3WKhIiQLCBMKB7BuuyFCnvwnpjeLiGafjIYr6CNBn83uzac1 QX9OBuzp91EVLGbBSwAFyyxALhporUh4pDe27SqJbwg15kQd6tDp2f7423M6AoQGkEDMdzaBWRTu2UrMenzaqDOpFpilHA%3D%3D&return_url=https%3A %2F%2Fapp.test.com%2Fstatic%2Fh5Conversion%2Findex.html¬ify_url=https%3A%2F%2Fapp.com%2Fcallback%2Fppywforkylin%2Fali Pay % 2 falipay % 2 f5103092247759423283 & version = 1.0 & app_id = 2021001145660238 & sign_type = RSA2 & timestamp = 2020-12-28 + 15% 3 a28%3 a39 & Alipay_sdk = alipay - SDK - Java - 3.4.49. ALL&format = json \ "> < input type = \ \ n" hidden \ "name = \" biz_content \" Value =\"{"body":"10 coins ","out_trade_no":"1231231233123123123","product_code":"QUICK_WAP_WAY","subject":"10 coins ","timeout_exp" ress":"2m","total_amount":"1"}\">\n<inpCopy the code
Insert the form directly into the page using innerHtml. Submit is not executed. Because HTML 5 specifies that the innerHTML insert is not executed
$ifame. InnerHtml = payForm; //HTML 5 specifies that the <script> tag inserted by innerHTML is not executed. $iframe.qeuerySelector('form').submit();Copy the code
After submitting the Form Form, alipay part of the code alipay Scheme evokes logic
// Android goes iframe
if (ua.indexOf('android') > -1 && !noIntentTest) {
canIntent = false;
}
/** * open client */
_AP.open = function (params) {
if(! domLoaded && (ua.indexOf('360 aphone') > -1 || canIntent)) {
var arg = arguments;
delayToRun = function () {
_AP.open.apply(null, arg);
delayToRun = null;
};
return;
}
if (locked) {
return;
}
locked = true;
var o;
// START:: Jump back Scheme processing
var iosScheme, androidScheme, backScheme;
if (backScheme) {
iosScheme = backScheme.ios;
androidScheme = backScheme.android;
try {
window.tracker.log({
code: 11.msg: 'Scheme source:'+ JSON.stringify(backScheme),
sampleRate: 1}); }catch(e){
console.warn('Scheme source error :', e)
}
}
if (typeof params === 'object') {
if (iosScheme) {
params.h5FromAppUrlScheme = iosScheme;
params.sourceSceneType = 'h5Route';
}
o = {
'ios': encodeURIComponent(JSON.stringify(params)),
'android': encodeURIComponent(params.dataString)
};
if (androidScheme) {
o.android = o.android + '&sourceSceneType=h5Route&h5FromAppUrlScheme=' + androidScheme
}
} else {
console.error('params error, pls use JSON format! ')}// END
// params fault tolerance
if (typeofo.ios ! = ='string') {
o.ios = ' ';
} else if(typeofo.android ! = ='string') {
o.android = ' ';
}
// nonsupport Android intent
if(! canIntent) {if(isAndroid) {
var alipaysUrl = 'alipays://platformapi/startApp? appId=54556654&orderSuffix=' + o.android +'#Intent; scheme=alipays; package=com.eg.android.AlipayGphone; end';
}
//fix for iOS QQ browser
else if (ua.indexOf('mqqbrowser') > -1) {
var alipaysUrl = 'alipay://alipayclient/? ' + o.android;
}
else {
var alipaysUrl = 'alipay://alipayclient/? ' + o.ios;
}
//FIXME:Check ios, not OS version
if ( ua.indexOf('qq/') > -1 || ( ua.indexOf('safari') > -1 && ua.indexOf('os 9_') > -1 ) || ( ua.indexOf('safari') > -1 && ua.indexOf('os 10_') > -1 ) || ( ua.indexOf('safari') > -1 && ua.indexOf('os 11_') > -1 ) || ( ua.indexOf('safari') > -1 && ua.indexOf('os 12_') > -1 ) || ( ua.indexOf('safari') > -1 && ua.indexOf('os 13_') > -1 ) || ( ua.indexOf('safari') > -1 && ua.indexOf('os 14_') > -1)) {var openSchemeLink = document.getElementById('openSchemeLink');
if(! openSchemeLink) { openSchemeLink =document.createElement('a');
openSchemeLink.id = 'openSchemeLink';
openSchemeLink.style.display = 'none';
document.body.appendChild(openSchemeLink);
}
//openSchemeLink.href = alipaysUrl;
// Oppo browser compatible writing method
openSchemeLink.onclick = function() {
window.location.href = alipaysUrl;
};
// trigger click
openSchemeLink.dispatchEvent(customClickEvent());
}
else {
var ifr = document.createElement('iframe');
ifr.src = alipaysUrl;
ifr.style.display = 'none';
document.body.appendChild(ifr);
}
$('.J-startapp').attr('href', alipaysUrl);
}
//support Android intent
else {
var packageKey = 'AlipayGphone';
var intentUrl = 'alipays://platformapi/startApp? appId=54545544&orderSuffix='+o.android+'#Intent; scheme=alipays; package=com.eg.android.'+ packageKey +'; end';
var openIntentLink = document.getElementById('openIntentLink');
if(! openIntentLink) { openIntentLink =document.createElement('a');
openIntentLink.id = 'openIntentLink';
openIntentLink.style.display = 'none';
document.body.appendChild(openIntentLink);
}
//openIntentLink.href = intentUrl;
// Oppo browser compatible writing method
openIntentLink.onclick = function() {
window.location.href = intentUrl;
};
// trigger click
openIntentLink.dispatchEvent(customClickEvent());
}
setTimeout(function () {
locked = false;
}, 2500)
Copy the code
Alipay results polling, and returnUrl logic
//
/ / polling
var payquery = function () {
if(stopQuery) { return }
var argumentsPayquery = arguments;
Zepto.ajax({
type: 'post'.url: '/h5/h5RoutePayResultQuery.json? h5_route_token=RZ42FugnN5SrDYUBQr3vTTeQg3magDmobilecashierRZ42&need_invoke_app=true'./*/h5/h5RoutePayResultQuery.json? h5_route_token=*/
data: {'_input_charset': 'utf-8'.'params': $('input[name=params]').val(),
'session': 'RZ42FugnN5SrDYUBQr3vTTeQg3magDmobilecashierRZ42'
},
timeout: 30000.dataType: 'json'.success: function (data) {
// Alipay client has been invoked
if(data.data.invokeAlipay && time){
time = 0;
}
/ / success
if(data.control_type == 'pay_success') {
if(data.data && data.data.returnUrl && data.data.returnUrl ! =' ') {
window.location.replace(decodeURIComponent(data.data.returnUrl)); }}// Continue polling
else if (data.control_type == 'h5_route_need_pay_query') {
if(! data.data.stopQuery) {setTimeout(function(){ argumentsPayquery.callee(); }, data.data.dismisstime); }}}}); }Copy the code
Subapp – Reload popover
Summary:
There needs to be a half-screen popup window for H5 recharge in the APP, and only wechat H5 payment is connected
Question:
- IPhone users cancel or do not return to app after completing payment after activating wechat app payment interface in H5
The reason:
- The UA of the client is faulty
Screen:
1. Ua comparison between the sub-app and the main app
The child app:
UserAgent % 20/3.9.0 _build119317%20 nettype/WiFi % 20 language/useful – Hans – CN),
The main app: Mozilla / 5.0% 20 (iPhone; % 20 CPU % 20 iphone % 20 2012 _4_1%20 like % 20 MAC OS % % 20 OS x % 20) % 20 applewebkit / 605.1.15%20 (KHTML, % 20 like % 20 gecko) % 20 mobile / 15 e148%20 20 nettype/WiFi / 1.8.8 _build132540% % 20 language/useful – Hans – CN)
Debugging: After adjusting userAgent to add mobile identity through whistle, the test is normal (it is speculated that there is ua judgment logic in the logic of clicking “Finish” or “cancel” in wechat payment interface to access redirectUrl with Safari)
Performance: After the subapp invokes wechat Payment, click Cancel, and the callback URL is not performed