| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- 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'
- import util from '@kit.ArkTS';
- @Component
- struct PrivacyPolicyPage {
- @Require fromText: string
- @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: this.fromText,
- controller: this.controller
- })
- .width('100%')
- .height('100%')
- .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) => {
- // this.controller.runJavaScript('document.forms[0].submit()')
- 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(_: string, fromText: string) {
- PrivacyPolicyPage({fromText})
- }
|