我在使用 MPG 时遇到问题。 支付源首先提供了 HTML 代码,我通过 API 请求获取了季节 ID。 https://mcb.gateway.mastercard.com/api/rest/version/75/merchant/{merchant-id}/session
HTML 读取会话 ID,但我在 Web 视图应该显示付款表单时遇到了这些错误
I/flutter (17252): JavaScript Console: Uncaught SecurityError: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
I/flutter (17252): JavaScript Console: Possible Unhandled Promise Rejection: SecurityError: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
造成这种情况的问题是什么?
代码
InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse(''),
),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
cacheEnabled: true,
useShouldOverrideUrlLoading: true,
javaScriptEnabled: true,
javaScriptCanOpenWindowsAutomatically: true,
mediaPlaybackRequiresUserGesture: false,
),
android: AndroidInAppWebViewOptions(
useHybridComposition: true,
domStorageEnabled: true,
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
)),
androidOnPermissionRequest: (controller, origin, resources) async {
return PermissionRequestResponse(
resources: resources,
action: PermissionRequestResponseAction.GRANT,
);
},
onWebViewCreated: (controller) async {
webView = controller;
await webView?.loadData(
//html content
data: '''
<html>
<head>
<meta name="viewport" content="width=device-width, initial- scale=1">
<script src="https://mcb.gateway.mastercard.com/static/checkout/checkout.min.js" data-error="errorCallback" data-cancel="cancelCallback"></script>
<script type="text/javascript">
function errorCallback(error) {
console.log(JSON.stringify(error));
}
function cancelCallback() {
console.log('Payment cancelled');
}
Checkout.configure({
session: {
id: '${state.id}'
}
});
</script>
</head>
<body>
...
<div id="embed-target"> </div>
<input type="button" value="Pay with Embedded Page" onclick="Checkout.showEmbeddedPage('#embed-target');" />
<input type="button" value="Pay with Payment Page" onclick="Checkout.showPaymentPage();" />
...
</body>
</html>
''',
mimeType: 'text/html',
);
},
onLoadError: (controller, url, code, message) {
print('Error loading $url: $code, $message');
},
onLoadStop: (controller, url) {},
onConsoleMessage: (controller, consoleMessage) {
final logMessage = consoleMessage.message;
print('JavaScript Console: $logMessage');
},
);
我了解我们都在致力于将 MPGS 支付集成到 Flutter 中。
在我最近的工作中,我还遇到了flutter_inappwebview包不支持本地存储的限制。您可以通过在 Github 上打开的此问题来确定。
为了解决这个问题,我评估了一些我尝试过的解决方案,可能会帮助您推进项目:
解决方案1:
我创建了一个 HTML 页面,其中包含加载 MPGS 集成所需的脚本和数据。
<html>
<head>
<script
src="https://test-gateway.mastercard.com/static/checkout/checkout.min.js"
data-error="errorCallback"
data-cancel="cancelCallback"
></script>
<script type="text/javascript">
const params = new URLSearchParams(document.location.search);
const sessionId = params.get("session_id");
function errorCallback(error) {
console.log(JSON.stringify(error));
}
function cancelCallback() {
console.log("Payment cancelled");
}
Checkout.configure({
session: {
id: `${sessionId}`,
},
}).then(() => {
Checkout.showPaymentPage();
});
</script>
</head>
</html>
此页面已上传到我们的服务器。
从移动端,我从服务器请求 HTML 页面,并将会话 ID 作为 URL 中的查询参数传递。 例如:
www.example.com/mpgs.html?session_id=xxxxxxxx
HTML 页面上的 MPGS 脚本可以从查询字符串中检索会话 ID 以初始化支付流程。 这允许我从我们自己的服务器上的远程 URL 加载 MPGS webview 内容,同时仍然从移动应用程序传递必要的会话 ID。然后,网络视图可以传达退款状态和令牌。
解决方案2:
我已将上述页面添加到应用程序资产项目中,并使用应用程序内本地主机服务器在本地托管页面HTML,像上面一样传递session_id(查询参数)并加载脚本。
我已经实现了以下代码:
定义变量
final InAppLocalhostServer localhostServer = InAppLocalhostServer();
然后初始化它
Future.microtask(() async => await localhostServer.start());
之后,添加了以下小部件
InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse(
"http://localhost:8080/assets/html_files/paymentGateWay.html?session_id=SESSION0002174711341F46647517L2")),
initialOptions: uiController.webViewOptions,
onProgressChanged: (controller, progress) =>
uiController.setLoadingProgress(progress / 100),
androidOnPermissionRequest: (controller, origin, resources) =>
uiController.getPermissionRequestResponse(resources),
onLoadError: (controller, url, code, message) {
print('Error loading $url: $code, $message');
},
onUpdateVisitedHistory: (controller, url, androidIsReload) {
print('sadsdasad');
print(url);
},
onLoadStop: (controller, url) {},
onConsoleMessage: (controller, consoleMessage) {
final logMessage = consoleMessage.message;
print('JavaScript Console: $logMessage');
},
);
虽然在本地托管 HTML 页面并重定向到 MPGS 是一个可行的解决方案,但 我认为存在需要考虑的限制: 应用程序需要允许 HTTP URL 方案才能在本地托管 HTML 页面。但是,出于安全和隐私原因,大多数应用程序默认不允许非 HTTPS 方案。
请告诉我您对解决方案 2 的看法。