- 使用hbuildx4.45(检查更新,已是最新)创建项目,点击运行到鸿蒙真机
- 将unpackage\debug\app-harmony-xxxx拷贝出来,进行配置相关,成功在真机上运行初始项目
- 将原始uni仓库中的package.json依赖更新为:
"dependencies": { "@dcloudio/uni-app": "3.0.0-4040520250104002", "@dcloudio/uni-app-harmony": "3.0.0-4040520250104002", "@dcloudio/uni-app-plus": "3.0.0-4040520250104002", "@dcloudio/uni-components": "3.0.0-4040520250104002", "@dcloudio/uni-h5": "3.0.0-4040520250104002", "@dcloudio/uni-mp-alipay": "3.0.0-4040520250104002", "@dcloudio/uni-mp-baidu": "3.0.0-4040520250104002", "@dcloudio/uni-mp-jd": "3.0.0-4040520250104002", "@dcloudio/uni-mp-kuaishou": "3.0.0-4040520250104002", "@dcloudio/uni-mp-lark": "3.0.0-4040520250104002", "@dcloudio/uni-mp-qq": "3.0.0-4040520250104002", "@dcloudio/uni-mp-toutiao": "3.0.0-4040520250104002", "@dcloudio/uni-mp-weixin": "3.0.0-4040520250104002", "@dcloudio/uni-mp-xhs": "3.0.0-4040520250104002", "@dcloudio/uni-quickapp-webview": "3.0.0-4040520250104002", "@dcloudio/uni-ui": "^1.5.3", "@types/fs-extra": "^11.0.4", "@types/lodash-es": "^4.17.12", "@vant/weapp": "^1.11.4", "@vueuse/core": "^10.9.0", "@vueuse/integrations": "^10.9.0", "@vueuse/shared": "^10.9.0", "async-validator": "^4.2.5", "axios": "^1.6.8", "archiver": "^7.0.1", "canvas-to-svg": "^1.0.3", "date-fns": "^3.6.0", "dateformat": "^5.0.3", "dijkstrajs": "^1.0.3", "fs-extra": "^11.2.0", "lodash-es": "^4.17.21", "mitt": "^3.0.1", "moment": "^2.30.1", "pinia": "2.0.36", "postcss-url": "^10.1.3", "svg64": "^2.0.0", "swiper": "^11.1.1", "uqrcodejs": "^4.0.7", "vite-plugin-remote-assets": "^0.4.1", "vue": "^3.5.12", "vue-awesome-swiper": "^5.0.1", "vue-demi": "^0.14.7", "vue-i18n": "^9.10.2", "weapp-polyfill": "^3.2.2", "weapp-qrcode": "^1.0.0", "wechat-utils": "0.0.1" }, "devDependencies": { "@dcloudio/types": "^3.4.8", "@dcloudio/uni-automator": "3.0.0-4040520250104002", "@dcloudio/uni-cli-shared": "3.0.0-4040520250104002", "@dcloudio/uni-stacktracey": "3.0.0-4040520250104002", "@dcloudio/uni-uts-v1": "3.0.0-4040520250104002", "@dcloudio/vite-plugin-uni": "3.0.0-4040520250104002", "@douyin-microapp/typings": "^1.2.2", "@typescript-eslint/eslint-plugin": "^7.4.0", "@typescript-eslint/parser": "^7.4.0", "@vue/compiler-sfc": "^3.4.21", "@vue/runtime-core": "^3.4.21", "@vue/tsconfig": "^0.1.3", "eslint": "^8.57.0", "eslint-plugin-vue": "^9.24.0", "http-server": "^14.1.1", "js-base64": "^3.7.7", "minimist": "^1.2.8", "miniprogram-api-typings": "^3.12.2", "miniprogram-ci": "^1.9.15", "prettier": "3.2.5", "qrcode": "^1.5.4", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.72.0", "strip-json-comments": "3.1.1", "tt-ide-cli": "^0.1.25", "typescript": "^4.9.5", "vite": "5.2.8", "vite-copy-plugin": "^0.4.0", "vite-plugin-replace-image-url": "^1.1.1", "vue-tsc": "^1.8.27" },
- pnpm run build项目,打包后的文件替换到新的鸿蒙基座中,运行到真机
- 对hx4.20鸿蒙基座中部分代码有过改动。但未对hx4.45基座进行过类似改造,可以参考试试...
hx4.20项目\entry\src\main\ets\uni-app\components\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 deviceInfo from '@ohos.deviceInfo'; import { UTSHarmony as UTSHarmony7, getWindowInfo as internalGetWindowInfo, getDeviceId as getDeviceId1 } from "@dcloudio/uni-app-harmony-framework"; import { GetWindowInfoResult } from '@dcloudio/uni-app-harmony';
interface Detail {}
interface Event {
detail: Detail
}
interface TitleUpdateEventDetail {
title?: string
}
interface TitleUpdateEvent extends Event {
detail: TitleUpdateEventDetail
}
interface ISystemInfoAppVersion {
name: string;
code: string;
}
@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)
}
customUserAgent() {
const appVersion: ISystemInfoAppVersion = UTSHarmony7.getAppVersion();
const windowInfo = internalGetWindowInfo() as GetWindowInfoResult;
// Mozilla/5.0 (Phone; OpenHarmony 5.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 ArkWeb/4.1.6.1 MobileHUAWEI emulator/(ZYWallet;1.0.0;100;harmonyos OS;0;387x836;3.25)
return ${this.controller.getUserAgent()} ${deviceInfo.brand} ${deviceInfo.productModel}/(ZYWallet;${appVersion.name};${appVersion.code};harmonyos OS;${deviceInfo.buildVersion};${windowInfo.screenWidth}x${windowInfo.screenHeight};${vp2px(1)})
;
}
build() {
Web({
src: this.src,
controller: this.controller
})
.overScrollMode(OverScrollMode.NEVER)
.geolocationAccess(true)
.domStorageAccess(true)
.imageAccess(true)
.fileAccess(true)
.onTitleReceive(event => {
console.log('onTitleReceive: ' + JSON.stringify(event?.title))
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(event.error.getErrorInfo())
}
})
.javaScriptProxy({
object: {
postMessage: (data: string) => {
// console.log('onPostMessage: ' + data)
try {
if (this.onMessage) {
this.onMessage({ detail: JSON.parse(data) })
}
} catch (error) {
console.error(ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}
);
}
},
postMessageToService: (data: string) => {
if (this.onPostMessageToService) {
this.onPostMessageToService({ detail: JSON.parse(data) })
}
}
},
name: '__uniappx',
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
})
.onControllerAttached(() => {
console.log("onControllerAttached");
try {
this.controller.setCustomUserAgent(this.customUserAgent());
console.log('setCustomUserAgent', this.controller.getCustomUserAgent())
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
})
.onLoadIntercept((event) => {
try {
let tempUrl = event.data.getRequestUrl();
console.info('onLoadIntercept:' + tempUrl)
if (tempUrl && tempUrl.startsWith('zywallet://')) {
if (this.onMessage) {
this.onMessage({ detail: tempUrl });
return true;
}
}
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
return false;
})
}
setSrc() {
this.controller.loadUrl(this.src)
}
}
> hx4.20项目\entry\src\main\ets\uni-app\components
``` javascript
import harmonyWebView from '@ohos.web.webview'
import picker from '@ohos.file.picker';
import { BusinessError } from '@ohos.base';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import deviceInfo from '@ohos.deviceInfo';
import { UTSHarmony as UTSHarmony7, getWindowInfo as internalGetWindowInfo, getDeviceId as getDeviceId1 } from "@dcloudio/uni-app-harmony-framework";
import { GetWindowInfoResult } from '@dcloudio/uni-app-harmony';
interface Detail {}
interface Event {
detail: Detail
}
interface TitleUpdateEventDetail {
title?: string
}
interface TitleUpdateEvent extends Event {
detail: TitleUpdateEventDetail
}
interface ISystemInfoAppVersion {
name: string;
code: string;
}
@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)
}
customUserAgent() {
const appVersion: ISystemInfoAppVersion = UTSHarmony7.getAppVersion();
const windowInfo = internalGetWindowInfo() as GetWindowInfoResult;
// Mozilla/5.0 (Phone; OpenHarmony 5.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 ArkWeb/4.1.6.1 MobileHUAWEI emulator/(ZYWallet;1.0.0;100;harmonyos OS;0;387x836;3.25)
return `${this.controller.getUserAgent()} ${deviceInfo.brand} ${deviceInfo.productModel}/(ZYWallet;${appVersion.name};${appVersion.code};harmonyos OS;${deviceInfo.buildVersion};${windowInfo.screenWidth}x${windowInfo.screenHeight};${vp2px(1)})`;
}
build() {
Web({
src: this.src,
controller: this.controller
})
.overScrollMode(OverScrollMode.NEVER)
.geolocationAccess(true)
.domStorageAccess(true)
.imageAccess(true)
.fileAccess(true)
.onTitleReceive(event => {
console.log('onTitleReceive: ' + JSON.stringify(event?.title))
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(event.error.getErrorInfo())
}
})
.javaScriptProxy({
object: {
postMessage: (data: string) => {
// console.log('onPostMessage: ' + data)
try {
if (this.onMessage) {
this.onMessage({ detail: JSON.parse(data) })
}
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
},
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
})
.onControllerAttached(() => {
console.log("onControllerAttached");
try {
this.controller.setCustomUserAgent(this.customUserAgent());
console.log('setCustomUserAgent', this.controller.getCustomUserAgent())
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
})
.onLoadIntercept((event) => {
try {
let tempUrl = event.data.getRequestUrl();
console.info('onLoadIntercept:' + tempUrl)
if (tempUrl && tempUrl.startsWith('zywallet://')) {
if (this.onMessage) {
this.onMessage({ detail: tempUrl });
return true;
}
}
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
return false;
})
}
setSrc() {
this.controller.loadUrl(this.src)
}
}
> hx4.20项目\entry\src\main\ets\pages\Page.ets
``` javascript
import {
WebNodeController,
callPageLifeCycle,
} from '../../resources/rawfile/uni-app/uni-app-harmony-framework-dev';
import {
TabBar,
TabBarState,
OnTabItemClickOptions,
createTabBarState,
createTabBarItem
} from '../uni-app/components/TabBar';
import { NavBar, ITitleNView } from '../uni-app/components/NavBar';
import { NodeController, window } from '@kit.ArkUI';
import { SafeAreaOffset } from '../uni-app/components/SafeAreaOffset';
import harmonyWebView from '@ohos.web.webview'
import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
@Observed
class PullToRefresh {
support?: boolean
constructor(pullToRefresh?: PullToRefresh) {
this.support = pullToRefresh?.support
}
}
@Observed
class ObservedPageStyle {
titleNView?: ITitleNView
pullToRefresh?: PullToRefresh
background?: string
backgroundTextStyle?: 'light' | 'dark'
marginTop?: number
paddingBottom?: number
constructor(style: ObservedPageStyle) {
this.titleNView = style.titleNView
this.pullToRefresh = new PullToRefresh(style.pullToRefresh)
this.background = style.background
this.backgroundTextStyle = style.backgroundTextStyle
this.marginTop = style.marginTop
this.paddingBottom = style.paddingBottom
let flag = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO;
let bundleInfo = bundleManager.getBundleInfoForSelfSync(flag)
let appId = bundleInfo.signatureInfo.appId;
console.log('get Appid:', appId);
}
}
@Observed
class ObservedChildren extends Array<NodeController> {
}
@Observed
class RefreshState {
refreshing?: boolean
onRefreshing?: () => void
onRefreshStateChange?: (state?: RefreshStatus) => void
constructor(state?: RefreshState) {
this.refreshing = state?.refreshing
this.onRefreshing = state?.onRefreshing
this.onRefreshStateChange = state?.onRefreshStateChange
}
}
@Observed
class SubPageState {
id: string
style: ObservedPageStyle
embedChildren: ObservedChildren
stackChildren: ObservedChildren
refreshState: RefreshState
constructor(id: string, style: ObservedPageStyle, embedChildren: NodeController[], stackChildren: NodeController[],
refreshState?: RefreshState) {
this.id = id
this.style = new ObservedPageStyle(style)
this.embedChildren = new ObservedChildren(...embedChildren)
this.stackChildren = new ObservedChildren(...stackChildren)
this.refreshState = new RefreshState(refreshState)
}
}
export function createSubPageState(options: SubPageState) {
return new SubPageState(options.id, options.style, options.embedChildren, options.stackChildren, options.refreshState)
}
export {
createTabBarState, createTabBarItem
}
interface NavBarState extends ITitleNView {
onBackClick?: (options: OnTabItemClickOptions) => void
}
@Component
struct PageChildren {
@ObjectLink children: ObservedChildren
build() {
Stack({ alignContent: Alignment.TopStart }) {
ForEach(this.children, (child: NodeController) => {
NodeContainer(child)
}, (_: object, index: number) => {
return '' + index
})
}
}
}
abstract class IWebNodeController extends NodeController {
abstract update: (options: Object) => void
}
interface IWebNodeStyle {
backgroundColor: string
}
@Component
struct PageContainer {
@ObjectLink subPage: SubPageState
@Require @Prop @Watch('pageStyleChange') style: ObservedPageStyle
webNode: IWebNodeController | null = null
pageStyleChange(style: ObservedPageStyle) {
this.updateWebNodeBackground({
backgroundColor: style.background
} as IWebNodeStyle)
}
updateWebNodeBackground(style: IWebNodeStyle) {
if (this.webNode) {
this.webNode.update({
backgroundColor: style.backgroundColor || Color.Transparent
} as IWebNodeStyle)
}
}
aboutToAppear(): void {
this.webNode = new WebNodeController(this.subPage.id) as IWebNodeController
this.updateWebNodeBackground({
backgroundColor: this.style.background
} as IWebNodeStyle)
}
build() {
Stack({ alignContent: Alignment.TopStart }) {
Stack({ alignContent: Alignment.TopStart }) {
PageChildren({ children: this.subPage.embedChildren })
NodeContainer(this.webNode)
.width('100%')
.height('100%')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
PageChildren({ children: this.subPage.stackChildren })
}
.width('100%')
.height('100%')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
.margin({
top: this.style.marginTop
})
}
.clip(true)
.width('100%')
.height('100%')
.padding({
bottom: this.style.paddingBottom
})
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
}
@Component
struct SubPage {
@ObjectLink subPage: SubPageState
@Require @Prop style: ObservedPageStyle
@ObjectLink refreshState: RefreshState
@Prop safeArea: SafeArea | undefined
@Builder
customRefreshComponent() {
Stack() {
Row() {
LoadingProgress().height(32)
.color(this.style.backgroundTextStyle === 'light' ? Color.White : '#5f5f5f')
}
.alignItems(VerticalAlign.Center)
}.width("100%").align(Alignment.Center)
}
build() {
Flex({
direction: FlexDirection.Column,
}) {
if (this.style.titleNView) {
NavBar({
titleNView: this.style.titleNView,
onBackClick: () => {
callPageLifeCycle('onBackPress', this)
}
})
}
Stack() {
if (this.style.pullToRefresh?.support) {
Refresh({
refreshing: $$this.refreshState.refreshing,
builder: this.customRefreshComponent()
}) {
PageContainer({ subPage: this.subPage, style: this.style })
}
.backgroundColor(this.style.background)
.onStateChange(status => {
this.refreshState.onRefreshStateChange?.(status)
})
.onRefreshing(() => {
this.refreshState.refreshing = true
this.refreshState.onRefreshing?.()
})
} else {
PageContainer({ subPage: this.subPage, style: this.style })
}
}
.clip(true)
.width('100%')
.flexGrow(1)
.flexBasis(1)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}.width('100%')
.height('100%')
.backgroundColor(this.style.background)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
}
@Observed
class ObservedPages extends Array<SubPageState> {
}
interface SafeAreaBottom {
offset?: string
}
interface SafeArea {
background?: string
bottom?: SafeAreaBottom
}
@Entry
@Component
struct Page {
mainWindow: window.Window = globalThis.mainWindow
@State pages: SubPageState[] = new ObservedPages()
@State safeArea: SafeArea | undefined = undefined
@State tabBar: TabBarState | undefined = undefined
@State navBar: NavBarState | undefined = undefined
build() {
Flex({
direction: FlexDirection.Column,
}) {
Stack() {
ForEach(this.pages, (subPage: SubPageState, index: number) => {
SubPage({
subPage: subPage,
style: subPage.style,
refreshState: subPage.refreshState,
safeArea: this.safeArea
})
}, (subPage: SubPageState, index: number) => {
return index + '-' + subPage.id
})
}
.width('100%')
.flexGrow(1)
.flexBasis(1)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
if (this.tabBar && this.tabBar.list && this.tabBar.list.length > 0) {
TabBar({
style: this.tabBar,
selectedIndex: this.tabBar.selectedIndex,
items: this.tabBar.list,
onTabItemClick: (options: OnTabItemClickOptions) => {
this.tabBar?.onClick?.(options)
}
})
.visibility(this.tabBar.visible === false ? Visibility.None : Visibility.Visible)
} else if (this.safeArea && this.safeArea?.bottom?.offset === 'auto') {
SafeAreaOffset({ type: 'bottom' })
}
}
.width('100%')
.height('100%')
.backgroundColor(this.safeArea?.background)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
aboutToAppear() {
// 配置Web开启调试模式
harmonyWebView.WebviewController.setWebDebuggingAccess(true);
callPageLifeCycle('aboutToAppear', this)
}
aboutToDisappear() {
callPageLifeCycle('aboutToDisappear', this)
}
onPageShow(): void {
callPageLifeCycle('onPageShow', this)
const style = this.pages[0]?.style;
console.log('onPageShow', 'style:' + style);
if (style) {
const styleString = JSON.stringify(style);
if (styleString && styleString.includes('"privacyMode":true')) {
//敏感信息页面禁止截屏、录屏
this.mainWindow.setWindowPrivacyMode(true)
console.log('onPageShow', 'setWindowPrivacyMode')
}
}
}
onPageHide(): void {
callPageLifeCycle('onPageHide', this)
this.mainWindow.setWindowPrivacyMode(false)
}
onBackPress(): boolean | void {
return callPageLifeCycle('onBackPress', this)
}
pageTransition() {
if (callPageLifeCycle('pageTransition', this).enter.push === 'none') {
PageTransitionEnter({ type: RouteType.Push, duration: 0 })
}
if (callPageLifeCycle('pageTransition', this).enter.pop === 'none') {
PageTransitionEnter({ type: RouteType.Pop, duration: 0 })
}
if (callPageLifeCycle('pageTransition', this).exit.push === 'none') {
PageTransitionExit({ type: RouteType.Push, duration: 0 })
}
if (callPageLifeCycle('pageTransition', this).exit.pop === 'none') {
PageTransitionExit({ type: RouteType.Pop, duration: 0 })
}
}
}
0 个回复