|
|
@@ -0,0 +1,320 @@
|
|
|
+import { promptAction, router } from '@kit.ArkUI'
|
|
|
+import { webview } from '@kit.ArkWeb'
|
|
|
+import { bundleManager, common } from '@kit.AbilityKit'
|
|
|
+import { BusinessError } from '@kit.BasicServicesKit'
|
|
|
+import { WebViewJavascriptBridge, WVJBResponseCallback } from '@yue/webview_javascript_bridge'
|
|
|
+
|
|
|
+
|
|
|
+@Component
|
|
|
+struct PrivacyPolicyPage {
|
|
|
+ @State targetUrl: string = ''
|
|
|
+ @State title: string = ''
|
|
|
+ // 是否有进度条
|
|
|
+ hasProgressBar: boolean = false
|
|
|
+ // 网络加载进度
|
|
|
+ @State progressNum: number = 0
|
|
|
+ // 网络是否在加载中
|
|
|
+ @State loading: boolean = true
|
|
|
+ // 是否显示
|
|
|
+ navBarShow: boolean = true
|
|
|
+ // 进入页面时,状态条颜色
|
|
|
+ onPageShowBarColor: StatusBarColor = StatusBarColor.Black
|
|
|
+ // 隐藏页面时,状态条颜色
|
|
|
+ onPageHideBarColor: StatusBarColor = StatusBarColor.Black
|
|
|
+ // 顶部安全高度
|
|
|
+ safeTop: number = AppStorage.get('safeTop') as number
|
|
|
+ // 底部安全高度
|
|
|
+ safeBottom: number = AppStorage.get('safeBottom') as number
|
|
|
+ controller: webview.WebviewController = new webview.WebviewController()
|
|
|
+ historyCurrIndex: number = 0
|
|
|
+ // WebViewJavascriptBridge 桥接
|
|
|
+ private bridge: WebViewJavascriptBridge | undefined;
|
|
|
+ private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
|
|
|
+ // 是否安装支付宝应用
|
|
|
+ private canOpenAlipays = false;
|
|
|
+ // 是否安装微信应用
|
|
|
+ private canOpenWechat = false;
|
|
|
+ // 是否已拉起微信支付
|
|
|
+ private isWeixinPay = false;
|
|
|
+ // 支付订单页url,如果成功拉起微信支付以后取消会回到app,此时需要跳到订单页
|
|
|
+ private orderUrl: string = '';
|
|
|
+ // 监听网页加载是否出错
|
|
|
+ @State loadError: boolean = false;
|
|
|
+ // 点击返回键需要直接退出web组件的url集合
|
|
|
+ private excludedUrlList: string[] = [
|
|
|
+ 'https://app.sightcloud.cn/storage/#/package',
|
|
|
+ 'https://app.aikancloud.com/storage/#/packageOrder',
|
|
|
+ 'https://wx.88iot.net'
|
|
|
+ ];
|
|
|
+
|
|
|
+ aboutToAppear(): void {
|
|
|
+ this.onPageShow()
|
|
|
+ }
|
|
|
+
|
|
|
+ onPageShow(): void {
|
|
|
+ // this.statusBarColorSelect(this.onPageShowBarColor)
|
|
|
+ // 判断是否安装支付宝
|
|
|
+ try {
|
|
|
+ this.canOpenAlipays = bundleManager.canOpenLink('alipays://');
|
|
|
+ this.canOpenWechat = bundleManager.canOpenLink('weixin://');
|
|
|
+ } catch (err) {
|
|
|
+ let message = (err as BusinessError).message;
|
|
|
+ console.log('canOpenLink call error:', message);
|
|
|
+ }
|
|
|
+ // 判断是否是跳转到微信以后再返回app,若是,则跳转到订单页,若没有拿到订单url,直接返回上一页
|
|
|
+ if (this.isWeixinPay) {
|
|
|
+ this.isWeixinPay = false
|
|
|
+ if (this.orderUrl) {
|
|
|
+ // 清跳转订单页
|
|
|
+ this.controller.loadUrl(this.orderUrl)
|
|
|
+ } else {
|
|
|
+ this.backMethod()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ onPageHide(): void {
|
|
|
+ this.statusBarColorSelect(this.onPageHideBarColor)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 状态条颜色选取函数
|
|
|
+ statusBarColorSelect(color: StatusBarColor) {
|
|
|
+ switch (color) {
|
|
|
+ case StatusBarColor.White:
|
|
|
+ // themeManager.settingStatusBarWhite()
|
|
|
+ break
|
|
|
+ case StatusBarColor.Black:
|
|
|
+ // themeManager.settingStatusBarBlack()
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ // themeManager.settingStatusBarBlack()
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 页面自行处理返回逻辑,不进行页面路由
|
|
|
+ onBackPress() {
|
|
|
+ this.backMethod()
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ backMethod() {
|
|
|
+ if (this.loadError) {
|
|
|
+ router.back()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const url = this.controller.getUrl()
|
|
|
+ if (this.excludedUrlList.some(item => url.startsWith(item))) {
|
|
|
+ router.back()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.historyCurrIndex > 0) {
|
|
|
+ this.controller.backward()
|
|
|
+ } else {
|
|
|
+ router.back()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ build() {
|
|
|
+ NavDestination() {
|
|
|
+ Column() {
|
|
|
+ if (this.navBarShow) {
|
|
|
+ // PrivacyPolicyPageTitle({ title: this.title })
|
|
|
+ }
|
|
|
+
|
|
|
+ Stack({ alignContent: Alignment.Top }) {
|
|
|
+ if (this.hasProgressBar && this.loading && !this.loadError) {
|
|
|
+ this.progress()
|
|
|
+ }
|
|
|
+ if (this.loadError) {
|
|
|
+ Column() {
|
|
|
+ Text('出错啦!点击空白处刷新')
|
|
|
+ .fontColor('#686868')
|
|
|
+ .fontSize(20)
|
|
|
+ }
|
|
|
+ // .width(StyleConstants.FULL_PARENT)
|
|
|
+ // .height(StyleConstants.FULL_PARENT)
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
+ .onClick(() => {
|
|
|
+ this.loadError = false
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Scroll() {
|
|
|
+ Web({ src: $rawfile('index.html'), controller: this.controller })
|
|
|
+ .geolocationAccess(false)
|
|
|
+ .domStorageAccess(true)
|
|
|
+ .mixedMode(MixedMode.Compatible)
|
|
|
+ .fileAccess(true)
|
|
|
+ .multiWindowAccess(true)
|
|
|
+ .onControllerAttached(() => {
|
|
|
+ this.setupWebViewJavascriptBridge();
|
|
|
+ })
|
|
|
+ .onProgressChange((date) => {
|
|
|
+ if (date) {
|
|
|
+ //记录加载进度
|
|
|
+ this.progressNum = date.newProgress
|
|
|
+ if (this.progressNum == 100) {
|
|
|
+ //加载完成进度条消失
|
|
|
+ animateTo({ duration: 800, delay: 300 }, () => {
|
|
|
+ this.loading = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .onRefreshAccessedHistory((event) => {
|
|
|
+ //H5页面间的跳转
|
|
|
+ // if (this.controller.getTitle().length < 5) {
|
|
|
+ // this.title = this.controller.getTitle()
|
|
|
+ // }
|
|
|
+ if (event) {
|
|
|
+ const history = this.controller.getBackForwardEntries()
|
|
|
+ this.historyCurrIndex = history.currentIndex
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .onPageBegin((event) => {
|
|
|
+ this.progressNum = 0
|
|
|
+ this.loading = true
|
|
|
+ })
|
|
|
+ .onLoadIntercept((event) => {
|
|
|
+ const isPayment = this.handlePaymentIntercept(event)
|
|
|
+ return isPayment
|
|
|
+ })
|
|
|
+ .onPageEnd((event) => {
|
|
|
+ if (this.orderUrl && event.url == this.orderUrl) {
|
|
|
+ this.controller.clearHistory()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .onErrorReceive((event) => {
|
|
|
+ if (event.request.getRequestUrl() == this.controller.getUrl()) {
|
|
|
+ console.error(`WebView load error: ${event.request.getRequestUrl()}, code: ${event.error.getErrorCode()}, message: ${event.error.getErrorInfo()}`);
|
|
|
+ this.loadError = true; // 显示错误页面
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ .margin({ bottom: this.navBarShow ? this.safeBottom : 0 })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .height('100%')
|
|
|
+ .padding({ top: this.navBarShow ? this.safeTop : 0, bottom: this.navBarShow ? this.safeBottom : 0 })
|
|
|
+ }
|
|
|
+ .hideTitleBar(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理支付相关的拦截逻辑
|
|
|
+ private handlePaymentIntercept(event: OnLoadInterceptEvent) {
|
|
|
+ let data = event.data;
|
|
|
+ let url = data.getRequestUrl();
|
|
|
+ console.log(`alipay: url: ${url}`);
|
|
|
+ // 点击商城回退时会触发该跳转,直接退出就好,不加载
|
|
|
+ if (url.includes('js_native://close')) {
|
|
|
+ router.back()
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ // 拉起支付宝支付
|
|
|
+ if (url.startsWith('alipays://platformapi/startApp')) {
|
|
|
+ if (this.canOpenAlipays) {
|
|
|
+ try {
|
|
|
+ this.context.openLink(url).then(() => {
|
|
|
+ console.info('open alipays success.');
|
|
|
+ }).catch((err: BusinessError) => {
|
|
|
+ console.error(`open alipays failed. Code is ${err.code}, message is ${err.message}`);
|
|
|
+ promptAction.showToast({ message: '打开支付宝失败' })
|
|
|
+ })
|
|
|
+ } catch (paramError) {
|
|
|
+ console.error(`Failed to start alipays. Code is ${paramError.code}, message is ${paramError.message}`)
|
|
|
+ promptAction.showToast({ message: '打开支付宝失败,请稍后重试' })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ promptAction.showToast({ message: '请先安装支付宝客户端' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 拉起微信支付链接,提前将支付成功微信支付跳转回app的订单页url保存,取消时同样需要跳转
|
|
|
+ if (url.startsWith('https://wx.tenpay.com')) {
|
|
|
+ // 提取 redirect_url 参数
|
|
|
+ const redirectUrl = this.getRedirectUrlFromTenpay(url);
|
|
|
+ if (redirectUrl) {
|
|
|
+ console.info('提取到重定向链接:', redirectUrl);
|
|
|
+ // 可以选择保存该链接用于后续操作
|
|
|
+ this.orderUrl = redirectUrl;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 拉起微信支付链接
|
|
|
+ if (url.startsWith('weixin://')) {
|
|
|
+ if (this.canOpenWechat) {
|
|
|
+ try {
|
|
|
+ this.context.openLink(url).then(() => {
|
|
|
+ // 拉起微信支付成功
|
|
|
+ this.isWeixinPay = true
|
|
|
+ console.info('open weixin success.');
|
|
|
+ }).catch((err: BusinessError) => {
|
|
|
+ console.error(`open weixin failed. Code is ${err.code}, message is ${err.message}`);
|
|
|
+ promptAction.showToast({ message: '打开微信失败' })
|
|
|
+ })
|
|
|
+ } catch (paramError) {
|
|
|
+ console.error(`Failed to start weixin. Code is ${paramError.code}, message is ${paramError.message}`)
|
|
|
+ promptAction.showToast({ message: '打开微信失败,请稍后重试' })
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ } else {
|
|
|
+ promptAction.showToast({ message: '请先安装微信客户端'})
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ // 从微信支付链接中提取 redirect_url 参数
|
|
|
+ private getRedirectUrlFromTenpay(url: string): string | null {
|
|
|
+ try {
|
|
|
+ // 使用正则提取 redirect_url 参数
|
|
|
+ const regex = /[?&]redirect_url=([^&]+)/;
|
|
|
+ const match = url.match(regex);
|
|
|
+ if (match && match[1]) {
|
|
|
+ let decodedUrl = decodeURIComponent(match[1]);
|
|
|
+ return decodedUrl;
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析 redirect_url 失败:', e);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Builder
|
|
|
+ progress() {
|
|
|
+ Progress({ value: this.progressNum, total: 100, type: ProgressType.Linear })
|
|
|
+ .color('#17ab19')
|
|
|
+ .zIndex(1)
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置 jsBridge
|
|
|
+ */
|
|
|
+ private setupWebViewJavascriptBridge() {
|
|
|
+ // 开启调试,控制台打印信息,默认无调试
|
|
|
+ WebViewJavascriptBridge.enableLogging();
|
|
|
+ // 创建 WebViewJavascriptBridge
|
|
|
+ this.bridge = new WebViewJavascriptBridge(this.controller);
|
|
|
+ this.registerHandlers(this.bridge)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 注册原生处理函数 (这里需要知道H5端的方法名)
|
|
|
+ private registerHandlers(bridge: WebViewJavascriptBridge) {
|
|
|
+ bridge.registerHandler('backToNative', (data: object, responseCallback: WVJBResponseCallback) => {
|
|
|
+ this.backMethod();
|
|
|
+ responseCallback(null);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export enum StatusBarColor {
|
|
|
+ White = 'White',
|
|
|
+ Black = 'Black',
|
|
|
+}
|
|
|
+
|
|
|
+@Builder
|
|
|
+function PrivacyPolicyBuilder() {
|
|
|
+ PrivacyPolicyPage()
|
|
|
+}
|