目前工程文件:SDK template-1.3.5.tgz
uni-app 开发鸿蒙应用 | uni-app官网 (dcloud.net.cn)
实现原理:uniapp使用webview组件打开支付宝链接,此时鸿蒙端web()组件onErrorReceive回调返回错误信息【ERR_UNKNOWN_URL_SCHEME】,然后在onErrorReceive回调中做应用间跳转手动打开app
1.uniapp---web组件打开支付宝链接
<template>
<view>
<!-- 支付宝支付 -->
<web-view :src="alipayUrl"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
alipayUrl: '',
}
},
onLoad(options) {
let infoUrl = JSON.parse(decodeURIComponent(options.info));
// scheme
this.alipayUrl = 'https://ds.alipay.com/?scheme=' + encodeURIComponent(
'alipays://platformapi/startapp?saId=10000007&qrcode=' + infoUrl);
},
}
</script>
<style scoped lang="scss">
</style>
这时harmony返回错误:ERR_UNKNOWN_URL_SCHEME
2.template---做应用间跳转
harmony应用间跳转文档地址:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/canopenlink-V5
2.1 module.json页面配置querySchemes
"querySchemes": [
"alipays", // 支付宝
"store", // 应用商城
],
2.2 WebView.ets页面做应用间跳转
WebView.ets 完整代码如下
import harmonyWebView from '@ohos.web.webview'
import picker from '@ohos.file.picker';
import { BusinessError } from '@ohos.base';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { bundleManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import OpenLinkOptions from '@ohos.app.ability.OpenLinkOptions';
import { promptAction } from '@kit.ArkUI';
const TAG: string = '[UIAbilityComponentsOpenLink]';
const DOMAIN_NUMBER: number = 0xFF00;
interface Detail {}
interface Event {
detail: Detail
}
interface TitleUpdateEventDetail {
title?: string
}
interface TitleUpdateEvent extends Event {
detail: TitleUpdateEventDetail
}
@Component
export struct WebView {
@Prop @Watch('setSrc') src: string
onMessage?: (event: Event) => void = undefined
onTitleUpdate?: (event: TitleUpdateEvent) => void = undefined
onPostMessageToService?: (event: Event) => void = undefined
exposeWebViewController?: (controller: harmonyWebView.WebviewController) => void = undefined
controller = new harmonyWebView.WebviewController()
aboutToAppear(): void {
this.exposeWebViewController?.(this.controller)
}
build() {
Web({
src: this.src,
controller: this.controller
})
.overScrollMode(OverScrollMode.NEVER)
.geolocationAccess(true)
.domStorageAccess(true)
.imageAccess(true)
.fileAccess(true)
.onTitleReceive(event => {
this.onTitleUpdate?.({
detail: {
title: event?.title
}
})
})
.onConsole(event => {
if (event) {
console.log('getMessage: ' + JSON.stringify(event.message.getMessage()))
}
return false
})
.onErrorReceive(event => {
if (event) {
console.error('getMessage: '+JSON.stringify(event.error.getErrorInfo()))
console.log('url:' + event.request.getRequestUrl())
// 判断应用是否可访问
try {
let link = event.request.getRequestUrl();
let canOpen = bundleManager.canOpenLink(link);
hilog.info(0x0000, 'testTag', 'canOpenLink successfully: %{public}s', JSON.stringify(canOpen));
if(canOpen){
// 应用间跳转
let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
let openLinkOptions: OpenLinkOptions = {
appLinkingOnly: false
};
try {
context.openLink(link, openLinkOptions)
.then(() => {
hilog.info(DOMAIN_NUMBER, TAG, 'open link success.');
}).catch((err: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, `open link failed. Code is ${err.code}, message is ${err.message}`);
})
} catch (paramError) {
hilog.error(DOMAIN_NUMBER, TAG, `Failed to start link. Code is ${paramError.code}, message is ${paramError.message}`);
}
}else{
promptAction.showToast({
message: 'APP 未安装',
duration: 2000,
bottom: '500lpx'
});
}
} catch (err) {
let message = (err as BusinessError).message;
hilog.error(0x0000, 'testTag', 'canOpenLink failed: %{public}s', message);
}
}
})
.javaScriptProxy({
object: {
postMessage: (data: string) => {
if (this.onMessage) {
this.onMessage({ detail: JSON.parse(data) })
}
},
postMessageToService: (data: string) => {
if (this.onPostMessageToService) {
this.onPostMessageToService({ detail: JSON.parse(data) })
}
}
},
name: '__uniapp_x_',
methodList: ['postMessage', 'postMessageToService'],
controller: this.controller
})
.onGeolocationShow((event) => {
let context = getContext(this) as common.UIAbilityContext;
let atManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(context, ["ohos.permission.APPROXIMATELY_LOCATION"]).then((data) => {
console.info('data authResults:' + data.authResults);
}).catch((error: BusinessError) => {
console.error(`Failed to request permissions from user. Code is ${error.code}, message is ${error.message}`);
})
AlertDialog.show({
title: '位置权限请求',
message: '是否允许获取位置信息',
primaryButton: {
value: 'cancel',
action: () => {
if (event) {
event.geolocation.invoke(event.origin, false, false);
}
}
},
secondaryButton: {
value: 'ok',
action: () => {
if (event) {
event.geolocation.invoke(event.origin, true, true);
}
}
},
cancel: () => {
if (event) {
event.geolocation.invoke(event.origin, false, false);
}
}
})
})
.onShowFileSelector((event) => {
// TODO 真机运行没有问题,模拟器运行后,选择图片后H5端无法获取图片信息
const selectOptions = new picker.PhotoSelectOptions();
const mode = event?.fileSelector.getMode();
const acceptType = event?.fileSelector.getAcceptType();
if (mode === 0) {
selectOptions.maxSelectNumber = 1;
}
if (acceptType) {
let type = "";
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.svg', '.webp'];
const containsImage = imageExtensions.some((ext: string): boolean => acceptType.includes(ext));
const videoExtensions =
['.mp4', '.mov', '.avi', '.mkv', '.flv', '.wmv', '.ogg', '.webm', 'mpg', 'mpeg', '.3gp', 'rm', 'rmvb',
'm4v', 'wma', 'mts'];
const containsVideo = videoExtensions.some((ext: string): boolean => acceptType.includes(ext));
if (containsImage && containsVideo) {
type = "IMAGE_VIDEO_TYPE";
} else if (containsImage) {
type = "IMAGE_TYPE";
} else if (containsVideo) {
type = "VIDEO_TYPE";
}
if (type) {
selectOptions.MIMEType = picker.PhotoViewMIMETypes[type]
}
}
let filePaths: Array<string> | null = null;
const viewPicker = new picker.PhotoViewPicker();
viewPicker.select(selectOptions).then((selectResult) => {
filePaths = selectResult.photoUris;
if (event) {
event.result.handleFileList(filePaths);
}
}).catch((err: BusinessError) => {
console.error(`Invoke viewPicker.select failed, code is ${err.code}, message is ${err.message}`);
})
return true
})
}
setSrc() {
this.controller.loadUrl(this.src)
}
}