Skip to content

Collection

1. Some payment channels need to open the third-party app for payment. If the webView does not handle it, the third-party app will fail to launch.

Question:

Some payment channels need to open the third-party app for payment. If the webView does not handle it, the third-party app will fail to launch. For example: when using GoPay to pay, the prompt "ERR_UNKNOWN_URL_SCHEME" error; LinePay, AirPay can not normally launch the corresponding app.

Answer:

If the container that opens the API is Android's WebView, you need to override WebViewClient. The following is the sample code.

java
public class TestWebViewClient extends WebViewClient {
    private static final String TAG = "TestWebViewClient";
    private Activity mContext;
    private List<String> HTTP_SCHEMES = Arrays.asList("http", "https");

    public TestWebViewClient(Activity context, WebView webView) {
        this.mContext = context;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        Log.d(TAG, "shouldOverrideUrlLoading url1=" + url);
        if(shouldOverrideUrlLoadingInner(view, url)) {
            return true;
        }
        return super.shouldOverrideUrlLoading(view, url);
    }

    @Override
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        String url = request != null && request.getUrl() != null ? request.getUrl().toString() : "";
        Log.d(TAG, "shouldOverrideUrlLoading url=" + (request != null ? request.getUrl().toString() : ""));
        if(shouldOverrideUrlLoadingInner(view, url)) {
            return true;
        }
        return super.shouldOverrideUrlLoading(view, request);
    }

    /**
     * Parse the url and open it by system function.
     *   case 1: deal "intent://xxxx" url.
     *   case 2: deal custom scheme. url
     * @param view: WebView
     * @param url
     * @return
     */
    private boolean shouldOverrideUrlLoadingInner(WebView view, String url) {
        if(!TextUtils.isEmpty(url)) {
            Uri uri = Uri.parse(url);
            if(uri != null) {
                if ("intent".equals(uri.getScheme())) {
                    try {
                        Intent intent = Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
                        if(intent != null) {
                            PackageManager pm = mContext.getPackageManager();
                            ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
                            if(info != null) {
                                mContext.startActivity(Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME));
                                return true;
                            }
                            else {
                                String fallbackUrl = intent.getStringExtra("browser_fallback_url");
                                if (!TextUtils.isEmpty(fallbackUrl)) {
                                    if(fallbackUrl.startsWith("market://"))
                                        startAppMarketWithUrl(mContext, fallbackUrl, false);
                                    else
                                        view.loadUrl(fallbackUrl);
                                    return true;
                                }
                            }
                        }
                    } catch (Exception e) {
                    }
                }
                if (!HTTP_SCHEMES.contains(uri.getScheme())) {
                    startUrl(mContext, url, true);
                    return true;
                }
            }
        }

        return false;
    }

    public static void startUrl(Context context, String url, boolean isNewTask) {
        if(context != null && !TextUtils.isEmpty(url)) {
            try {
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                if(isNewTask) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }
                context.startActivity(intent);

            } catch (Exception e) {
            }
        }
    }

    public static boolean hasActivity(Context context, Intent intent, String packageName) {
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> appList = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

        for (ResolveInfo info : appList) {
            if (info.activityInfo.packageName.equals(packageName))
                return true;
        }
        return false;
    }

    public static void startAppMarketWithUrl(Context context, String url, boolean forceUseGoogle) {
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            if (forceUseGoogle || hasActivity(context, intent, "com.android.vending"))
                intent.setPackage("com.android.vending");
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        } catch (Exception e) {
            try {
                startUrl(context, url, true);
            } catch (Exception e1) {}
        }
    }
}

click to downloadTestWebViewClient.java

2. When opening DANA payment, the page shows blank or "The network connection is unstable. Please try again later."

Question:

API standard deposit access method, open the DANA payment method, the page prompts an error, the phenomenon seen is blank, the actual page is relatively large, and the page error can be seen on the mobile page: "The network connection is unstable. Please try again later."

Anser:

If the container to open PaySDK is Android WebView, you need to set the WebSettings property of webView, the code is as follows

webSettings.setDomStorageEnabled(true);
webSettings.setTextZoom(100);
webSettings.setUseWideViewPort(true);

3. How to return to your APP after successful payment

Anser:

Open the cash register url in your own APP, and open the jump address (front-end callback address frontCallBackUrl) after the payment is completed, which is also inside the app. If you use an external browser to open the URL of the cash register, when the payment is completed and open the jump address (front-end callback address frontCallBackUrl), it is opened in the external browser. If you want to jump to the inside of the app, you need to jump through (schema DeepLink) change.

4. Asynchronous callback notification considerations

Anser:

The callback address must actually exist; Protocol format: application/json; Protocol return content: Please check【Callback Notification】 The problem of unreachable addresses (if the merchant server has restrictions on access to external IP addresses, the payermax server IP address needs to be added to the whitelist of the merchant server.

5. After clicking the "Confirm Payment" button, the follow-up payment page is not opened

Question:

API standard deposit access method, after clicking the "Confirm Payment" button, the follow-up payment page is not opened

Anser:

If the container that opens the API is Android's WebView, you need to do the following processing on the WebView, the following is the sample code:

mWebView.setWebViewClient(new WebViewClient());

6. Entering the cashier, the page prompts "The format of the request parameter is wrong"

Question:

The merchant uses String.format(Locale.default(), "%.2f", price) to format the amount, causing the amount format to be garbled

Anser:

Since Locale.getDefault() obtains the locale of the region where the current device is located, the formatted strings are different in different regions. It is recommended to use String. format(Locale. ENGLISH, "%.2f", price)

7. When using UPI to pay, the interface appears and there is no way to exit

Quesition:

Use UPI payment to enter the channel page, operate and then click the back button, there is no way to return to the previous page or after exiting, the cashier cannot be opened after entering again.

Anser:

If the merchant leaves the webView, use "webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);" to close the current JS thread. Need to be modified to "webView.loadUrl("about:blank");"

8. Adaptation issues such as incomplete display of payment methods or confusing styles on the cashier page

Question:

If the payment method on the cashier page is incompletely displayed or the style is confusing, for example:Sample.png

Anser:

Merchants need to set the following parameters of webView:
mWebView.getSettings().setTextZoom(100);

9.The soft keyboard covers the input box when paying

Question:

When paying, some input methods need to enter the mobile phone number or email address. At this time, click the input box, and the soft keyboard will cover the input box.

Anser:

If the above problem occurs, you need to check the container as follows:

  1. Do not set full screen mode
  2. windowSoftInputMode can not be set or set to adjustResize, do not set to adjustPan
  3. If it is an immersive status bar, you need to set fitSystemWindows=true in the layout

10. The URI sent by the merchant to PayerMax is capitalized at the beginning of APP://, why did we change it to start with app:// when redirecting?

Because the browser and webview automatically convert, the scheme is not case-sensitive in the browser, and will be uniformly converted to lowercase. When configuring in the manifest, the scheme and host must be all lowercase

11. What is the reason why the page reports this kind of error 'X-Frame-Options'

Generally, the channel side page does not support iframe nesting, please check whether X-Frame-Options is set in the web service.

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);

        webSettings.setSupportMultipleWindows(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

        webSettings.setPluginState(WebSettings.PluginState.ON); //enable plugin. Ex: flash. deprecated on API 18
        //whether the zoom controls display on screen.
        webSettings.setBuiltInZoomControls(true);
        webSettings.setSupportZoom(true);
        webSettings.setDisplayZoomControls(false);

        //disable the webview font size changes according the phone font size.
        webSettings.setTextZoom(100);
        webSettings.setSaveFormData(true);
        webSettings.setUseWideViewPort(true);
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setAllowFileAccess(true);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
            CookieManager.getInstance().setAcceptThirdPartyCookies(this, true);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            webSettings.setAllowUniversalAccessFromFileURLs(true);
        }

        webSettings.setAppCacheEnabled(true);
        String appCacheDir = getDir("cache", Context.MODE_PRIVATE).getPath();
        webSettings.setAppCachePath(appCacheDir);
        webSettings.setAppCacheMaxSize(1024*1024*20);
        webSettings.setDomStorageEnabled(true);
        webSettings.setDatabaseEnabled(true);
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);

        try {
            mWebView.removeJavascriptInterface("searchBoxJavaBridge_");
            mWebView.removeJavascriptInterface("accessibility");
            mWebView.removeJavascriptInterface("accessibilityTraversal");
        } catch (Exception e) {}

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mWebView.enableSlowWholeDocumentDraw();
        }

13. The page reports "net::ERR_CACHE_MISS"

This is because the network permission configuration is abnormal. You can change the permission configuration attempt in AndroidManifest.xml. old: new: Reference:https://stackoverflow.com/questions/30637654/android-webview-gives-neterr-cache-miss-message

14. The system browser is normal, but using iOS wkwebview to jump will fail, and the page cannot be opened normally

The possible reason is that wkwebview changes the url encoding, resulting in an abnormal link. # in the link is urlEncoded to %23. You can add code logic to webview to avoid abnormal encoding of url

OC
-(NSString *)WM_FUNC_urlEncode:(NSString *)urlStr{
NSMutableCharacterSet *set  = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[set addCharactersInString:@"#"];
return [urlStr stringByAddingPercentEncodingWithAllowedCharacters:set];
}
swift 4.0
func WM_FUNC_urlEncode(_ urlStr:String) -> String {
if urlStr.isEmpty {
return ""
}
var charSet = CharacterSet.urlQueryAllowed
charSet.insert(charactersIn: "#")
let encodingURLStr = urlStr.addingPercentEncoding(withAllowedCharacters: charSet)
return encodingURLStr ?? ""
}

The following imitates the oc writing method: CharacterSet converts NSMutableCharacterSet to operate

func WM_FUNC_urlEncode(_ urlStr:String) -> String {
if urlStr.isEmpty {
return ""
}
let charSet = CharacterSet.urlQueryAllowed as NSCharacterSet
let mutSet = charSet.mutableCopy() as! NSMutableCharacterSet
mutSet.addCharacters(in: "#")
let encodingURLStr = urlStr.addingPercentEncoding(withAllowedCharacters: mutSet as CharacterSet)
return encodingURLStr ?? ""
}

func WM_FUNC_urlEncode(_ urlStr:String) -> String {
if urlStr.isEmpty {
return ""
}
let charSet = NSMutableCharacterSet()
charSet.formUnion(with: CharacterSet.urlQueryAllowed)
charSet.addCharacters(in: "#")
let encodingURLStr = urlStr.addingPercentEncoding(withAllowedCharacters: charSet as CharacterSet)
return encodingURLStr ?? ""
}

Refernce: https://www.jianshu.com/p/e4938ada31e6

15.Phones above Android 9.0 cannot open the page, and the protocol is changed to https. Those below 9.0 are fine, but those above are not.

The reason may be that Android P restricts network requests for plaintext traffic of the http protocol, and non-encrypted traffic requests will be banned by the system. You can replace the relevant api/page with https protocol If you still need to use http, you can make Android webview support http protocol through the following methods:

Method One:

  1. Create a new xml directory under the res directory, and create a new network_security_config.xml file under the xml directory:
xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <base-config cleartextTrafficPermitted="true" />
</network-security-config>

2.AndroidManifest.xml xml copy code

xml
<application android:networkSecurityConfig="@xml/network_security_config">
  <!--android9.0 adaptation-->
  <uses-library android:name="org.apache.http.legacy" android:required="false" />
</application>

Method Two: AndroidManifest.xml added:

xml
<application android:usesCleartextTraffic="true">

Refernce https://juejin.cn/post/6844903813929762824

16.The webview loads the page and reports an error, net::ERR_BLOCKED_BY_RESPONSE.

The reason for this is that this address is not supported for use in iframes. It is recommended that you open the page address directly instead of using it in an iframe.

【Disbursement】

17.Mistakenly think that the payment interface response code APPLY_SUCCESS means payment is successful

Question:

The response code received from the withdrawal interface is APPLY_SUCCESS, which means the payment is successful

Anser:

The response code APPLY_SUCCESS just means that the current protocol response is successful; if you want to check whether the payment is successful, the callback result of the server shall prevail (the merchant passes in or configures the callback address of the server) or the active query shall prevail.

【Parameter Configuration】

1.How to generate keys?

You can log in to the merchant platform to generate and reset keys through the "Development Parameters" channel. When configuring, it is necessary to distinguish between the test environment and the formal environment.

2.How to add callback address?

PayerMax supports two ways to set the callback address:

  1. Operators or super administrators with the authority to develop parameters can generate and modify callback addresses in the "Development Parameters" channel on the merchant platform.
  2. Pass in the callback address when placing an order. Note: If there is a conflict between the callback address you pass in and the callback address configured on the merchant platform, the callback address you pass in shall prevail.

3.Why didn't I receive the callback notification?

  1. Please confirm whether to set the callback address.
  2. Please confirm whether the callback address is filled in correctly. If there is still a problem, please contact the PayerMax platform to find out the reason.

Released under the MIT License.