xugenyuan

ref |> 必修--文章详情页H5外链鸿蒙版跳转页面后展示效果与安卓/IOS不一致

http://192.168.1.3:8080/zentao/bug-view-19286.html
@@ -66,4 +66,10 @@ export class SpConstants{ @@ -66,4 +66,10 @@ export class SpConstants{
66 static GETUI_PUSH_DEVICE_TOKEN = "deviceToken" 66 static GETUI_PUSH_DEVICE_TOKEN = "deviceToken"
67 //link 67 //link
68 static HAS_LINK="has_link" 68 static HAS_LINK="has_link"
  69 +
  70 + // 是否开启H5白名单
  71 + static H5_WHITE_LIST_ENABLE ="h5_whilte_list_enable"
  72 + static H5_WHITE_LIST_LAST_DATA_MD5 ="h5_whilte_list_last_data_md5"
  73 +
  74 +
69 } 75 }
1 1
2 import fs from '@ohos.file.fs'; 2 import fs from '@ohos.file.fs';
3 import { BusinessError } from '@kit.BasicServicesKit'; 3 import { BusinessError } from '@kit.BasicServicesKit';
  4 +import { util } from '@kit.ArkTS';
4 5
5 export class FileUtils { 6 export class FileUtils {
6 7
@@ -31,4 +32,26 @@ export class FileUtils { @@ -31,4 +32,26 @@ export class FileUtils {
31 }) 32 })
32 }) 33 })
33 } 34 }
  35 +
  36 + static readFile(path: string): ArrayBuffer {
  37 + try {
  38 + let stat = fs.statSync(path)
  39 + let fd = fs.openSync(path, fs.OpenMode.READ_ONLY).fd;
  40 + let length = stat.size
  41 + let buf = new ArrayBuffer(length);
  42 + fs.readSync(fd, buf)
  43 + fs.closeSync(fd)
  44 + return buf
  45 + } catch (e) {
  46 + console.log("FileUtils - readFilePicSync " + e)
  47 + return new ArrayBuffer(0)
  48 + }
  49 + }
  50 +
  51 + static readFileAsString(path: string): string {
  52 + const data = FileUtils.readFile(path)
  53 + let decoder = util.TextDecoder.create('utf-8');
  54 + let str = decoder.decodeToString(new Uint8Array(data));
  55 + return str
  56 + }
34 } 57 }
1 import { SpConstants } from 'wdConstant/Index'; 1 import { SpConstants } from 'wdConstant/Index';
2 -import { DeviceUtil, SPHelper, StringUtils } from 'wdKit/Index'; 2 +import { DeviceUtil, Logger, SPHelper, StringUtils } from 'wdKit/Index';
3 import { HttpRequest } from '../http/HttpRequest'; 3 import { HttpRequest } from '../http/HttpRequest';
  4 +import { http } from '@kit.NetworkKit';
  5 +import fs from '@ohos.file.fs';
  6 +import { BusinessError } from '@kit.BasicServicesKit';
  7 +import { JSON } from '@kit.ArkTS';
4 8
5 const TAG: string = '[HttpUtils]' 9 const TAG: string = '[HttpUtils]'
6 10
@@ -81,4 +85,37 @@ export class HttpUtils { @@ -81,4 +85,37 @@ export class HttpUtils {
81 } 85 }
82 return true 86 return true
83 } 87 }
  88 +
  89 + static downloadUrlToPathWithout(url: string, toFilePath: string): Promise<boolean> {
  90 + Logger.debug(TAG, "will donwload url:" + url + " ======> " + toFilePath);
  91 +
  92 + return new Promise((reslove, fail) => {
  93 +
  94 + let httpRequest = http.createHttp()
  95 + httpRequest.request(url, (err, data) => {
  96 +
  97 + if (!err && data.responseCode == http.ResponseCode.OK) {
  98 + let imgFile = fs.openSync(toFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  99 + let wroteLength = 0
  100 + fs.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen: number) => {
  101 + Logger.debug(TAG, "write data to file succeed and size is:" + writeLen);
  102 + wroteLength = writeLen
  103 + }).catch((err: BusinessError) => {
  104 + Logger.error(TAG, "write data to file failed with error message: " + err.message + ", error code: " + err.code);
  105 + }).finally(() => {
  106 + fs.closeSync(imgFile);
  107 + httpRequest.destroy()
  108 +
  109 + reslove(wroteLength > 0)
  110 + });
  111 + return
  112 + }
  113 +
  114 + Logger.error(TAG, "download failed " + JSON.stringify(err));
  115 + httpRequest.destroy()
  116 + fail("failed")
  117 + });
  118 +
  119 + })
  120 + }
84 } 121 }
@@ -114,6 +114,9 @@ struct LaunchPage { @@ -114,6 +114,9 @@ struct LaunchPage {
114 if (!dataModelStr) { 114 if (!dataModelStr) {
115 //直接跳转首页 115 //直接跳转首页
116 WDRouterRule.jumpWithReplacePage(WDRouterPage.mainPage) 116 WDRouterRule.jumpWithReplacePage(WDRouterPage.mainPage)
  117 +
  118 + //同意隐私协议后每次启动app请求启动页相关数据,并更新数据
  119 + this.requestLaunchPageData();
117 return 120 return
118 } 121 }
119 122
@@ -2,22 +2,26 @@ @@ -2,22 +2,26 @@
2 import LaunchDataModel from '../viewModel/LaunchDataModel' 2 import LaunchDataModel from '../viewModel/LaunchDataModel'
3 3
4 import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest'; 4 import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
5 -import { HttpUrlUtils, ResponseDTO } from 'wdNetwork/Index';  
6 -import { DisplayUtils, Logger, SPHelper } from 'wdKit/Index'; 5 +import { HttpUrlUtils, HttpUtils, ResponseDTO } from 'wdNetwork/Index';
  6 +import { AppUtils, DisplayUtils, Logger, SPHelper } from 'wdKit/Index';
7 import { SpConstants } from 'wdConstant/Index'; 7 import { SpConstants } from 'wdConstant/Index';
  8 +import { FileUtils } from '@ohos/imageknife';
8 9
9 10
10 export class LaunchPageModel { 11 export class LaunchPageModel {
11 12
12 getLaunchPageData(): Promise<LaunchDataModel> { 13 getLaunchPageData(): Promise<LaunchDataModel> {
13 return new Promise<LaunchDataModel>((success, fail) => { 14 return new Promise<LaunchDataModel>((success, fail) => {
14 - HttpRequest.get<ResponseDTO<LaunchDataModel>>(HttpUrlUtils.getLaunchPageDataUrl()+ `?height=${DisplayUtils.getDeviceHeight()}&width=${DisplayUtils.getDeviceWidth()}`).then((data: ResponseDTO<LaunchDataModel>) => { 15 + HttpRequest.get<ResponseDTO<LaunchDataModel>>(HttpUrlUtils.getLaunchPageDataUrl()+ `?height=${DisplayUtils.getDeviceHeight()}&width=${DisplayUtils.getDeviceWidth()}`)
  16 + .then(async (data: ResponseDTO<LaunchDataModel>) => {
15 if (!data || !data.data) { 17 if (!data || !data.data) {
16 fail("数据为空") 18 fail("数据为空")
  19 + LaunchPageModel.dealWithLaunchDataModel()
17 return 20 return
18 } 21 }
19 if (data.code != 0) { 22 if (data.code != 0) {
20 fail(data.message) 23 fail(data.message)
  24 + LaunchPageModel.dealWithLaunchDataModel()
21 return 25 return
22 } 26 }
23 // Logger.debug("LaunchPageModel获取启动相关数据获取成功:success ", JSON.stringify(data)) 27 // Logger.debug("LaunchPageModel获取启动相关数据获取成功:success ", JSON.stringify(data))
@@ -27,6 +31,8 @@ export class LaunchPageModel { @@ -27,6 +31,8 @@ export class LaunchPageModel {
27 // console.log(obj) 31 // console.log(obj)
28 SPHelper.default.saveSync(SpConstants.APP_LAUNCH_PAGE_DATA_MODEL,obj) 32 SPHelper.default.saveSync(SpConstants.APP_LAUNCH_PAGE_DATA_MODEL,obj)
29 33
  34 + LaunchPageModel.dealWithLaunchDataModel(data.data)
  35 +
30 }, (error: Error) => { 36 }, (error: Error) => {
31 // Logger.debug("LaunchPageModel获取启动相关数据获取失败:error ", error.toString()) 37 // Logger.debug("LaunchPageModel获取启动相关数据获取失败:error ", error.toString())
32 fail(error.message) 38 fail(error.message)
@@ -34,6 +40,47 @@ export class LaunchPageModel { @@ -34,6 +40,47 @@ export class LaunchPageModel {
34 }) 40 })
35 } 41 }
36 42
  43 + static async dealWithLaunchDataModel(model?: LaunchDataModel) {
  44 + if (!model) {
  45 + let dataModelStr = SPHelper.default.getSync(SpConstants.APP_LAUNCH_PAGE_DATA_MODEL, '') as string
  46 + model = JSON.parse(dataModelStr ?? "")
  47 + if (!model) { return }
  48 + }
  49 +
  50 + LaunchPageModel.dealWithWhiteListWith(model)
  51 +
  52 + // TODO: others
  53 +
  54 +
  55 +
  56 +
  57 +
  58 + }
  59 +
  60 + static async dealWithWhiteListWith(model: LaunchDataModel) {
  61 + SPHelper.default.saveSync(SpConstants.H5_WHITE_LIST_ENABLE, model.operationUrl.enabled)
  62 +
  63 + const lastMD5 = SPHelper.default.getSync(SpConstants.H5_WHITE_LIST_LAST_DATA_MD5, "") as string
  64 + if (lastMD5 && lastMD5 == model.operationUrl.md5) {
  65 + // MD5未变更,保持已下载的白名单
  66 + if (AppUtils.gotApplicationContextFunc) {
  67 + let filePath = AppUtils.gotApplicationContextFunc().getApplicationContext().filesDir + "/h5_whitelist.txt"
  68 + if (FileUtils.getInstance().exist(filePath)) {
  69 + return
  70 + }
  71 + }
  72 + }
  73 +
  74 + if (!AppUtils.gotApplicationContextFunc) {
  75 + return
  76 + }
  77 + let filePath = AppUtils.gotApplicationContextFunc().getApplicationContext().filesDir + "/h5_whitelist.txt"
  78 + const result = await HttpUtils.downloadUrlToPathWithout(model.operationUrl.linkUrl, filePath)
  79 + if (result) {
  80 + SPHelper.default.saveSync(SpConstants.H5_WHITE_LIST_LAST_DATA_MD5, model.operationUrl.md5 ?? "")
  81 + }
  82 + }
  83 +
37 getMournsInfoData(): Promise<LaunchDataModel> { 84 getMournsInfoData(): Promise<LaunchDataModel> {
38 return new Promise<LaunchDataModel>((success, fail) => { 85 return new Promise<LaunchDataModel>((success, fail) => {
39 HttpRequest.get<ResponseDTO<LaunchDataModel>>(HttpUrlUtils.getLaunchPageDataUrl()).then((data: ResponseDTO<LaunchDataModel>) => { 86 HttpRequest.get<ResponseDTO<LaunchDataModel>>(HttpUrlUtils.getLaunchPageDataUrl()).then((data: ResponseDTO<LaunchDataModel>) => {
@@ -62,10 +62,8 @@ struct H5TipsPage { @@ -62,10 +62,8 @@ struct H5TipsPage {
62 62
63 // 获取系统剪贴板对象 63 // 获取系统剪贴板对象
64 let systemPasteboard = pasteboard.getSystemPasteboard(); 64 let systemPasteboard = pasteboard.getSystemPasteboard();
65 - // 创建一条纯文本类型的剪贴板内容对象createPlainTextData  
66 - let pasteData = pasteboard.createPlainTextData(this.webUrl);  
67 - pasteData.addTextRecord(this.webUrl);  
68 - // 将数据写入系统剪贴板 65 + let pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, this.webUrl)
  66 + // // 将数据写入系统剪贴板
69 systemPasteboard.setData(pasteData).then(()=>{ 67 systemPasteboard.setData(pasteData).then(()=>{
70 // 存入成功,处理正常场景 68 // 存入成功,处理正常场景
71 ToastUtils.shortToast('复制成功') 69 ToastUtils.shortToast('复制成功')
  1 +import { FileUtils as imageFileUtils } from '@ohos/imageknife'
  2 +import { Action } from 'wdBean'
  3 +import { AppUtils, FileUtils, SPHelper } from 'wdKit'
  4 +import { JumpInterceptorAction, RouterJumpInterceptor, WDRouterPage } from 'wdRouter'
  5 +import { JSON, uri } from '@kit.ArkTS'
  6 +import { SpConstants } from 'wdConstant'
  7 +import { router } from '@kit.ArkUI'
  8 +
  9 +interface WhiteListModel {
  10 + whiteurls: string[]
  11 +}
  12 +
  13 +class DefaultWebJumpHandler implements JumpInterceptorAction {
  14 +
  15 + /// 说明是调用了跳转 WDRouterPage.loginPage 页面的行为
  16 + on(params?: object | undefined, singleMode?: boolean | undefined): boolean {
  17 + let action = params as Action
  18 +
  19 + if (action.params?.url) {
  20 +
  21 + const whiteListEnable = SPHelper.default.getSync(SpConstants.H5_WHITE_LIST_ENABLE, false) as boolean
  22 + if (!whiteListEnable) {
  23 + return false
  24 + }
  25 +
  26 + const jumpHost = new uri.URI(action.params?.url).host
  27 + const list = this.configWhiteLists()
  28 + list.push(...this.localWhiteLists())
  29 +
  30 + const inWhilteList = list.filter((host) => {
  31 + return host == jumpHost
  32 + }).length > 0
  33 +
  34 + if (false == inWhilteList) {
  35 + router.pushUrl({url: WDRouterPage.h5TipsPage.url(), params: action.params})
  36 + return true
  37 + }
  38 + }
  39 + return false
  40 + }
  41 +
  42 + configWhiteLists() : string[] {
  43 + let list : string[] = []
  44 +
  45 + if (!AppUtils.gotApplicationContextFunc) {
  46 + return list
  47 + }
  48 + let filePath = AppUtils.gotApplicationContextFunc().getApplicationContext().filesDir + "/h5_whitelist.txt"
  49 + const jsonStr = FileUtils.readFileAsString(filePath)
  50 + const listObj = JSON.parse(jsonStr) as WhiteListModel
  51 + if (listObj && listObj.whiteurls && listObj.whiteurls.length) {
  52 +
  53 + const urls = listObj.whiteurls.map((obj) => {
  54 + if (obj.startsWith("http")) {
  55 + return new uri.URI(obj).host
  56 + }
  57 + return new uri.URI("https://" + obj).host
  58 + })
  59 +
  60 + list.push(...urls)
  61 + }
  62 + return list
  63 + }
  64 +
  65 + localWhiteLists() : string[] {
  66 + const list = [
  67 + "https://cdnpeoplefrontdev.aikan.pdnews.cn",
  68 + "https://cdnpeoplefrontsit.aikan.pdnews.cn",
  69 + "https://cdnpeoplefrontuat.aikan.pdnews.cn",
  70 + "https://cdnpeoplefront.aikan.pdnews.cn",
  71 + "https://pd-people-uat.pdnews.cn",
  72 + "https://pd-people-sit.pdnews.cn",
  73 + "https://pd-people-dev.pdnews.cn",
  74 + "https://www.peopleapp.com",
  75 + "https://h5.peopleapp.com"
  76 + ]
  77 + return list.map((url) => {
  78 + return new uri.URI(url).host
  79 + })
  80 + }
  81 +}
  82 +
  83 +export function registerDefaultWebJumpInterceptor() {
  84 + RouterJumpInterceptor.register(WDRouterPage.defaultWebPage, new DefaultWebJumpHandler())
  85 + RouterJumpInterceptor.register(WDRouterPage.h5NewsWebPage, new DefaultWebJumpHandler())
  86 +}
@@ -27,6 +27,7 @@ import { initGlobalPlayerSettings } from 'wdPlayer/src/main/ets/utils/GlobalSett @@ -27,6 +27,7 @@ import { initGlobalPlayerSettings } from 'wdPlayer/src/main/ets/utils/GlobalSett
27 import { BackgroundAudioController } from 'wdPlayer/Index' 27 import { BackgroundAudioController } from 'wdPlayer/Index'
28 import { SpConstants } from 'wdConstant' 28 import { SpConstants } from 'wdConstant'
29 import { WDShareBase } from 'wdShareBase/Index'; 29 import { WDShareBase } from 'wdShareBase/Index';
  30 +import { registerDefaultWebJumpInterceptor } from '../pages/web/WebPageJumpInterceptor'
30 31
31 const TAG = "[StartupManager]" 32 const TAG = "[StartupManager]"
32 33
@@ -59,6 +60,7 @@ export class StartupManager { @@ -59,6 +60,7 @@ export class StartupManager {
59 KVStoreHelper.init(context) 60 KVStoreHelper.init(context)
60 // 路由注册 61 // 路由注册
61 registerRouter(); 62 registerRouter();
  63 + registerDefaultWebJumpInterceptor()
62 64
63 // 设置全局context 65 // 设置全局context
64 AppUtils.gotApplicationContextFunc = () => { 66 AppUtils.gotApplicationContextFunc = () => {