fanmingyou3_wd

工程级一多开发:三层架构规范

工程级一多开发:多设备部署设计
Showing 100 changed files with 4082 additions and 34 deletions

Too many changes to show.

To preserve performance only 100 of 100+ files are displayed.

... ... @@ -5,13 +5,13 @@
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.cer",
"storePassword": "0000001A76406594DCD45689E6888037F1FA52EA0D15317DD495835E1F8D18BEF743FCEB51D881F01BA2",
"certpath": "C:\\Users\\PC\\.ohos\\config\\default_sight_harmony_vDjosN2opayZneQDLiBs3Lc0sT1uPzRAYaDxxv2LWEQ=.cer",
"storePassword": "0000001A87430EDC6C0D1CD6A6473A6D385177DBFF70325BBD48C7E491A0D9B37F91920FD46D82B2436B",
"keyAlias": "debugKey",
"keyPassword": "0000001ACD3163BEAB09744DEA803A35F7B90073531926D60C13C3BA4F277C41CDB92A46819ED663CD31",
"profile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.p7b",
"keyPassword": "0000001A8E615E1CB276AA122C291AFBCDFF792FEE8AA618B186EE7C99220C7F549B8C2ED6A209703D75",
"profile": "C:\\Users\\PC\\.ohos\\config\\default_sight_harmony_vDjosN2opayZneQDLiBs3Lc0sT1uPzRAYaDxxv2LWEQ=.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.p12"
"storeFile": "C:\\Users\\PC\\.ohos\\config\\default_sight_harmony_vDjosN2opayZneQDLiBs3Lc0sT1uPzRAYaDxxv2LWEQ=.p12"
}
}
],
... ... @@ -35,8 +35,8 @@
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"name": "phone",
"srcPath": "./products/phone",
"targets": [
{
"name": "default",
... ... @@ -48,7 +48,7 @@
},
{
"name": "wdConstant",
"srcPath": "./wdConstant",
"srcPath": "./commons/wdConstant",
"targets": [
{
"name": "default",
... ... @@ -60,7 +60,7 @@
},
{
"name": "wdKit",
"srcPath": "./wdKit",
"srcPath": "./commons/wdKit",
"targets": [
{
"name": "default",
... ... @@ -72,7 +72,7 @@
},
{
"name": "wdBean",
"srcPath": "./wdBean",
"srcPath": "./features/wdBean",
"targets": [
{
"name": "default",
... ... @@ -84,7 +84,7 @@
},
{
"name": "wdComponent",
"srcPath": "./wdComponent",
"srcPath": "./features/wdComponent",
"targets": [
{
"name": "default",
... ... @@ -96,7 +96,7 @@
},
{
"name": "wdNetwork",
"srcPath": "./wdNetwork",
"srcPath": "./commons/wdNetwork",
"targets": [
{
"name": "default",
... ... @@ -108,7 +108,7 @@
},
{
"name": "wdRouter",
"srcPath": "./wdRouter",
"srcPath": "./commons/wdRouter",
"targets": [
{
"name": "default",
... ... @@ -120,11 +120,11 @@
},
{
"name": "wdJsBridge",
"srcPath": "./wdJsBridge"
"srcPath": "./commons/wdJsBridge"
},
{
"name": "wdWebComponent",
"srcPath": "./wdWebComponent",
"srcPath": "./commons/wdWebComponent",
"targets": [
{
"name": "default",
... ... @@ -148,7 +148,7 @@
// },
{
"name": "wdPlayer",
"srcPath": "./wdPlayer",
"srcPath": "./features/wdPlayer",
"targets": [
{
"name": "default",
... ... @@ -160,7 +160,7 @@
},
{
"name": "wdDetailPlayApi",
"srcPath": "./wdDetailPlayApi",
"srcPath": "./features/wdDetailPlayApi",
"targets": [
{
"name": "default",
... ... @@ -172,7 +172,7 @@
},
{
"name": "wdDetailPlayShortVideo",
"srcPath": "./wdDetailPlayShortVideo",
"srcPath": "./features/wdDetailPlayShortVideo",
"targets": [
{
"name": "default",
... ... @@ -184,7 +184,7 @@
},
{
"name": "wdDetailPlayVod",
"srcPath": "./wdDetailPlayVod",
"srcPath": "./features/wdDetailPlayVod",
"targets": [
{
"name": "default",
... ... @@ -196,7 +196,7 @@
},
{
"name": "wdDetailPlayLive",
"srcPath": "./wdDetailPlayLive",
"srcPath": "./features/wdDetailPlayLive",
"targets": [
{
"name": "default",
... ...
export { CommonConstants } from './src/main/ets/constants/CommonConstants';
export { BreakpointConstants } from './src/main/ets/constants/BreakpointConstants';
export { ConfigConstants } from './src/main/ets/constants/ConfigConstants';
// enum
export { BottomNavi } from './src/main/ets/enum/BottomNavi';
export { CompStyle } from './src/main/ets/enum/CompStyle';
export { CompType } from './src/main/ets/enum/CompType';
export { NetDataStatusType } from './src/main/ets/enum/NetDataStatusType';
export { ViewType } from './src/main/ets/enum/ViewType';
export { DurationEnum } from './src/main/ets/enum/DurationEnum';
export { ScreenType } from './src/main/ets/enum/ScreenType';
\ No newline at end of file
... ...
{
"license": "Apache-2.0",
"devDependencies": {},
"author": "",
"name": "wdconstant",
"description": "Please describe the basic information.",
"main": "Index.ets",
"version": "1.0.0",
"dependencies": {}
}
... ...
/**
* Constants for breakpoint.
*/
export class BreakpointConstants {
/**
* Breakpoints that represent smaller device types.
* 最小宽度
*/
static readonly BREAKPOINT_XS: string = 'xs';
/**
* Breakpoints that represent small device types.
* 小宽度
*/
static readonly BREAKPOINT_SM: string = 'sm';
/**
* Breakpoints that represent middle device types.
* 中等宽度
*/
static readonly BREAKPOINT_MD: string = 'md';
/**
* Breakpoints that represent large device types.
* 大宽度
*/
static readonly BREAKPOINT_LG: string = 'lg';
/**
* Breakpoints that represent extra-large device types.
* 特大宽度
*/
// static readonly BREAKPOINT_XL: string = 'xl';
/**
* Breakpoints that represent extra-extra-large device types.
* 超大宽度
*/
// static readonly BREAKPOINT_XXL: string = 'xxl';
}
\ No newline at end of file
... ...
/**
* The constant of Common.
*/
export class CommonConstants {
// offset
static readonly ZERO: number = 0;
static readonly NO_INDEX: number = -1;
static readonly NO_LENGTH: number = 0;
/**
* 布局相关.
*/
static readonly FULL_PARENT: string = '100%';
static readonly FULL_WIDTH: string = '100%';
static readonly FULL_HEIGHT: string = '100%';
/**
* Component opacity value: 1.
*/
static readonly FULL_OPACITY: number = 1;
}
;
... ...
/**
* Config Constants.
*/
export class ConfigConstants {
/**
* 应用id/appId
*
*/
static readonly appId: string = "";
/**
* 终端id/terminalId
*
*/
static readonly terminalId: string = "android";
/**
* 36_渠道编码(sappType)
*
*/
// static readonly appType: string = "2"; // wap
static readonly appType: string = "3"; // 手机客户端App(安卓)
static readonly clientType: string = "";
/**
* SourceID
*
*/
static readonly sourceId: string = "";
/**
* 产品渠道应用对照关系:
*/
static readonly appCode: string = "83092caa603a421aa0222308b3f6b27a";
/**
* 基线代码和客户端应用版本号规范
*/
static readonly ptvCode: string = "";
/**
* 省份code/province(02->上海)
*/
static readonly province: string = "02";
/**
* 正在播放的节目ID
*/
static playingContentId?: string = undefined
/**
* 设备Id/deviceId
* 设备Id或者能标识请求端的唯一标识
*/
static readonly DEVICE_ID: string = "5bfed7be-0497-487f-990b-991e5b828a6e";
/**
* base url VOD
*/
static readonly BASE_URL_VOD: string = "";
/**
* base url Live
*/
static readonly BASE_URL_LIVE: string = "";
/**
* 获取用户信息的服务器
*/
static readonly BASE_URL: string = "";
/**
* 内容列表路径
*/
static readonly CONTENT_LIST_PATH: string = "/display/v4/static";
/**
* 电视台(直播)列表路径
*/
static readonly LIVE_TV_PATH: string = "/live/v2/tv-data";
/**
* 临时的详情URL
*/
static readonly DETAIL_URL = "https://pd-people-uat.pdnews.cn/h/contentTop/110?hiddenTopNavigation=true"
}
\ No newline at end of file
... ...
/**
* 常见图片宽/高比
*/
export const enum AspectRatioEnum {
// 常见纵向比例
ASPECT_RATIO_2_3 = 2 / 3,
ASPECT_RATIO_3_4 = 3 / 4,
ASPECT_RATIO_4_5 = 4 / 5,
ASPECT_RATIO_5_7 = 5 / 7,
ASPECT_RATIO_9_16 = 9 / 16,
ASPECT_RATIO_10_16 = 10 / 16,
ASPECT_RATIO_9_21 = 9 / 21,
// 正方形
ASPECT_RATIO_1_1 = 1 / 1,
// 常见横向比例
ASPECT_RATIO_7_5 = 7 / 5,
ASPECT_RATIO_5_4 = 5 / 4,
ASPECT_RATIO_4_3 = 4 / 3,
ASPECT_RATIO_3_2 = 3 / 2,
ASPECT_RATIO_16_10 = 16 / 10,
ASPECT_RATIO_16_9 = 16 / 9,
ASPECT_RATIO_21_9 = 21 / 9,
// 其他常见比例
ASPECT_RATIO_2_1 = 2 / 1, // banner图宽高比
ASPECT_RATIO_1_2 = 1 / 2,
ASPECT_RATIO_75_45 = 75 / 45, // 角标宽高比
}
... ...
/**
* 底部导航 Bottom navigation item的下标/索引
* 新闻 人民号、 视频、 服务、 我的
*/
export const enum BottomNavi {
NEWS = 0,
PEOPLE,
VIDEO,
SERVICE,
MINE,
}
... ...
/**
* 组件Style/展示样式
*/
export const enum CompStyle {
Label_03 = 'Label-03', // 标题卡:icon+文字
Carousel_Layout_01 = 'Zh_Carousel_Layout-01', // 通用轮播卡:视频、直播、活动、专题、榜单、外链
Carousel_Layout_02 = 'Carousel_Layout-02', // 直播轮播卡:直播
Single_Row_01 = 'Zh_Single_Row-01', // 三格方形小卡(排名):专题、活动
Zh_Single_Row_01 = 'Zh_Single_Row-01', // 横划卡
Single_Row_02 = 'Zh_Single_Row-02', // 通用横划卡:视频、直播、专题
Single_Row_03 = 'Single_Row-03', // 直播横划卡:直播
Single_Row_04 = 'Single_Row-04', // 三格方形小卡:专题、活动
Single_Row_05 = 'Single_Row-05', // 专题横划卡:视频、直播、专题、活动、榜单、外链
Single_Column_01 = 'Single_Column-01', // 大卡横屏视频:视频、直播
Single_Column_02 = 'Single_Column-02', // 活动卡:活动
Single_Column_03 = 'Single_Column-03', // 地域榜单:榜单
Single_Column_04 = 'Single_Column-04', // 大卡横屏(带背景):视频、直播
Single_Column_05 = 'Single_Column-05', // 海报图卡:/
Single_Column_06 = 'Single_Column-06', // 留言板卡:/
Zh_Single_Column_02 = 'Zh_Single_Column-02', // 头图卡
Grid_Layout_01 = 'Grid_Layout-01', // 横屏宫格卡:视频、直播
Grid_Layout_02 = 'Grid_Layout-02', // 竖屏宫格卡:视频、直播、榜单
Masonry_Layout_01 = 'Masonry_Layout-01', // 双列瀑布流/瀑布流卡:视频、直播、专题、活动
Title_Abbr_01 = '11', // 标题缩略
Title_All_01 = '3', // 全标题
Single_ImageCard_03 = '13',//单图卡:3行标题
Single_ImageCard_01 = '6',//单图卡,竖图
ZhGrid_Layout_03 = 'Zh_Grid_Layout-03', //金刚位卡
Album_Card_01 = '17' //图卡集
}
... ...
/**
* 组件Type/展示类型
*/
export const enum CompType {
LABEL = 'LABEL', // 标题组件
CAROUSEL_LAYOUT = 'CAROUSEL_LAYOUT', // 轮播组件,即Banner/焦点图
SINGLE_ROW = 'SINGLE_ROW', // 单行组件
SINGLE_COLUMN = 'SINGLE_COLUMN', // 单列组件
GRID_LAYOUT = 'GRID_LAYOUT', // 网格组件
MASONRY_LAYOUT = 'MASONRY_LAYOUT', // 瀑布流组件
}
... ...
/**
* 时间跨度/延时枚举常量值
* duration/delay/interval
*/
export const enum DurationEnum {
DURATION_MS_50 = 50, // 50毫秒
DURATION_MS_100 = 100, // 50毫秒
DURATION_MS_1000 = 1000, // 1秒/1000ms
DURATION_MS_1500 = 1500, // 1.5秒
DURATION_1 = 1000, // 1秒
DURATION_2 = 2000, // 2秒
DURATION_3 = 3000, // 3秒
DURATION_4 = 4000, // 4秒
}
... ...
/**
* 请求网络数据状态类型
*/
export const enum NetDataStatusType {
// 已初始化,但尚未发出请求
INITIAL = 0,
// 请求已取消/或无需网络请求/或不关心请求结果/或调用方没有设置回调callback
CANCEL,
// 已发出请求,但请求尚未返回;
LOADING,
// 请求已失败返回;
FAILED,
// 请求已成功返回;
LOADED
}
\ No newline at end of file
... ...
/**
* view展示种类
*/
export const enum ViewType {
// 已初始化,但尚未发出请求
INITIAL = 0,
// 加载中:已发出请求,但请求尚未返回;
LOADING,
// 数据加载失败(重试)/failure
ERROR,
// 结果为空/无数据/空view
EMPTY,
// 已加载结束/非失败/非空/可以是仅一页数据,即楼层数据列表PAGE_GROUP_LIST/
LOADED,
// 已加载的是tab导航数据(可嵌套page的楼层列表)
NAV_BAR
}
\ No newline at end of file
... ...
{
"module": {
"name": "wdConstant",
"type": "shared",
"description": "$string:shared_desc",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true
}
}
\ No newline at end of file
... ...
{
"color": [
{
"name": "white",
"value": "#FFFFFF"
}
]
}
\ No newline at end of file
... ...
{
"string": [
{
"name": "shared_desc",
"value": "全局常量"
}
]
}
\ No newline at end of file
... ...
export default class BuildProfile {
static readonly HAR_VERSION = '1.0.0';
static readonly BUILD_MODE_NAME = 'debug';
static readonly DEBUG = true;
}
\ No newline at end of file
... ...
export { BridgeWebViewControl } from './src/main/ets/core/BridgeWebViewControl'
export { BridgeHandler } from './src/main/ets/core/BridgeHandler'
export { Callback } from './src/main/ets/core/BridgeHandler'
export { BridgeUtil } from './src/main/ets/utils/BridgeUtil'
... ...
import { harTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}
... ...
{
"license": "Apache-2.0",
"devDependencies": {},
"author": "",
"name": "wdjsbridge",
"description": "Please describe the basic information.",
"main": "Index.ets",
"version": "1.0.0",
"dependencies": {}
}
... ...
// 事件对象,同wdBean的Action
export interface Action {
type: string;
// params?: Params; // 参数集合
}
\ No newline at end of file
... ...
import { StringUtils } from '../utils/StringUtils';
/**
* 消息Message
*/
export class CallBackMessage {
callbackId: string = ""; //callbackId
responseId: string = ""; //responseId
responseData: string = ""; //responseData
data?: string; //data of message
handlerName: string = ""; //name of handler
/**
* TODO 待验证
* @returns
*/
toJson(): string {
let cloneObject:object = JSON.parse(JSON.stringify(this))
return StringUtils.escapeDoubleQuotes(JSON.stringify(cloneObject))
}
/**
* TODO 待验证
* @param jsonStr
* @returns
*/
toList(jsonStr: string): Array<CallBackMessage> {
return JSON.parse(jsonStr)
}
}
\ No newline at end of file
... ...
import { Action } from './Action';
/**
* 消息Message
*/
export class Message {
callbackId: string = ""; //callbackId
responseId: string = ""; //responseId
responseData: string = ""; //responseData
data?: Action; //data of message
handlerName: string = ""; //name of handler
/**
* TODO 待验证
* @returns
*/
toJson(): string {
let jsonString: string = JSON.stringify(this)
return jsonString
}
/**
* TODO 待验证
* @param jsonStr
* @returns
*/
toList(jsonStr: string): Array<Message> {
return JSON.parse(jsonStr)
}
}
\ No newline at end of file
... ...
import { Action } from '../bean/Action'
/**
* 注册回调接口
*/
export type Callback = (data: string) => void
export interface BridgeHandler {
handle: (data: Action, f: Callback) => void
}
export class DefaultBridgeHandler implements BridgeHandler {
handle(data: Action, f: Callback) {
//1,2.3
f("DefaultHandler response data")
}
}
\ No newline at end of file
... ...
import webview from '@ohos.web.webview';
import HashMap from '@ohos.util.HashMap';
import { BridgeHandler, DefaultBridgeHandler, Callback } from './BridgeHandler';
import { BridgeUtil } from '../utils/BridgeUtil';
import { Message } from '../bean/Message';
import { CallBackMessage } from '../bean/CallBackMessage';
import { StringUtils } from '../utils/StringUtils';
const TAG = 'BridgeWebViewControl';
export class BridgeWebViewControl extends webview.WebviewController {
/**
*
*/
private responseCallbacks: HashMap<string, Callback> = new HashMap<string, Callback>()
/**
*
*/
private messageHandlers: HashMap<string, BridgeHandler> = new HashMap()
/**
* 页面加载前,不能处理消息
*/
private uniqueId = 0;
registerHandler(handlerName: string, handler: BridgeHandler) {
if (handler != null) {
this.messageHandlers.set(handlerName, handler)
}
}
unregisterHandler(handlerName: string) {
if (handlerName != null) {
this.messageHandlers.remove(handlerName);
}
}
/**
* @param url
* @param returnCallback
*/
loadUrlCustom(url: string, returnCallback: Callback) {
this.loadUrl(url)
this.responseCallbacks.set(BridgeUtil.parseFunctionName(url), returnCallback);
}
/**
* 刷新消息
*/
flushMessageQueue() {
this.loadUrlCustom(BridgeUtil.JS_FETCH_QUEUE_FROM_JAVA, (data: string) => {
let list: Array<Message> = JSON.parse(data)
if (list == null || list.length == 0) {
return
}
list.forEach(value => {
let responseId: string = value.responseId
// 是否是response CallBackFunction,收到消息,
if (StringUtils.isNotEmpty(responseId)) {
let call: Callback = this.responseCallbacks.get(responseId)
let responseData: string = value.responseData;
if (StringUtils.isEmpty(responseData) || call === undefined) {
return
}
call(responseData)
this.responseCallbacks.remove(responseId)
} else {
let responseFunction: Callback;
let callbackId: string = value.callbackId
if (StringUtils.isNotEmpty(callbackId)) {
responseFunction = (data: string) => {
let msg: CallBackMessage = new CallBackMessage()
msg.responseId = callbackId
msg.responseData = data
this.queueMessage(msg)
}
} else {
responseFunction = (data: string) => {
//TODO 更换log输出方式
// Logger.info(TAG, `default response:: ${data}`);
}
}
let handle: BridgeHandler
if (StringUtils.isNotEmpty(value.handlerName)) {
handle = this.messageHandlers.get(value.handlerName)
} else {
handle = new DefaultBridgeHandler()
}
if (handle != undefined && value.data != undefined) {
handle.handle(value.data, responseFunction)
}
}
})
})
}
private queueMessage(msg: CallBackMessage) {
// //TODO
this.dispatchMessage(msg);
// }
}
/**
* 消息分发,最终执行js方法
* @param msg
*/
private dispatchMessage(msg: CallBackMessage) {
let messageJson: string = msg.toJson()
// messageJson = messageJson.replace("%7B", encodeURIComponent("%7B"));
// messageJson = messageJson.replace("%7D", encodeURIComponent("%7D"));
// messageJson = messageJson.replace("%22", encodeURIComponent("%22"));
let javascriptCommand: string = StringUtils.formatStringForJS(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson);
this.runJavaScript(javascriptCommand)
}
/**
* native 主动调用JSBridge方法
* @param msg
*/
callHandle(handlerName: string, data: string, callBack: Callback) {
this.doSend(handlerName, data, callBack)
}
private doSend(handlerName: string, data: string, callBack: Callback) {
let msg: CallBackMessage = new CallBackMessage()
if (StringUtils.isNotEmpty(data)) {
msg.data = data
}
if (StringUtils.isNotEmpty(handlerName)) {
msg.handlerName = handlerName
}
if (callBack != undefined) {
let callbackId: string = StringUtils.formatStringForJS(BridgeUtil.CALLBACK_ID_FORMAT, ++this.uniqueId + (BridgeUtil.UNDERLINE_STR + new Date().getTime()));
this.responseCallbacks.set(callbackId, callBack)
msg.callbackId = callbackId
}
this.queueMessage(msg);
}
handlerReturnData(url: string) {
let functionName: string = BridgeUtil.getFunctionFromReturnUrl(url);
let callback = this.responseCallbacks.get(functionName);
let data: string = BridgeUtil.getDataFromReturnUrl(url);
if (callback != undefined) {
callback(data)
this.responseCallbacks.remove(functionName)
}
}
//TODO
clean() {
this.responseCallbacks.clear()
this.messageHandlers.clear()
this.uniqueId = 0
}
}
... ...
import webview from '@ohos.web.webview';
import { ResourceManager } from './ResourceManager';
export class BridgeUtil {
static readonly YY_OVERRIDE_SCHEMA = "yy://";
static readonly YY_RETURN_DATA = BridgeUtil.YY_OVERRIDE_SCHEMA + "return/";
static readonly YY_FETCH_QUEUE = BridgeUtil.YY_RETURN_DATA + "_fetchQueue/";
static readonly EMPTY_STR = "";
static readonly UNDERLINE_STR = "_";
static readonly SPLIT_MARK = "/";
static readonly CALLBACK_ID_FORMAT = "JAVA_CB_%s";
static readonly JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');";
static readonly JS_FETCH_QUEUE_FROM_JAVA = "javascript:WebViewJavascriptBridge._fetchQueue();";
static readonly JAVASCRIPT_STR = "javascript:";
// 例子 javascript:WebViewJavascriptBridge._fetchQueue(); --> _fetchQueue
static parseFunctionName(jsUrl: string): string {
return jsUrl.replace("javascript:WebViewJavascriptBridge.", "").replace("();", "");
}
static getDataFromReturnUrl(url: string): string {
if (url.startsWith(BridgeUtil.YY_FETCH_QUEUE)) {
// return = [{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}]
return url.replace(BridgeUtil.YY_FETCH_QUEUE, BridgeUtil.EMPTY_STR);
}
// temp = _fetchQueue/[{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}]
let temp = url.replace(BridgeUtil.YY_RETURN_DATA, BridgeUtil.EMPTY_STR);
let functionAndData = temp.split(BridgeUtil.SPLIT_MARK);
if (functionAndData.length < 2) {
return ""
}
let result = ""
functionAndData.forEach((value) => {
result = result + value
});
return result
}
/**
* TODO
*/
static releaseWebView() {
}
// 获取到传递信息的方法
// url = yy://return/_fetchQueue/[{"responseId":"JAVA_CB_1_360","responseData":"Javascript Says Right back aka!"}]
static getFunctionFromReturnUrl(url: string): string {
let temp = url.replace(BridgeUtil.YY_RETURN_DATA, BridgeUtil.EMPTY_STR);
let functionAndData = temp.split(BridgeUtil.SPLIT_MARK);
if (functionAndData.length >= 1) {
// functionAndData[0] = _fetchQueue
return functionAndData[0];
}
return ""
}
/**
* 这里只是加载lib包中assets中的 WebViewJavascriptBridge.js
* @param controller
* @param path 路径
*/
static webViewLoadLocalJs(context: Context, controller: webview.WebviewController) {
ResourceManager.getResourcesText(context, "WebViewJavascriptBridge.js").then((str) => {
//执行js注入
controller.runJavaScriptExt('javascript:' + str).then((msg) => {
console.log("Js注入结果:" + msg.getString());
})
})
}
}
\ No newline at end of file
... ...
import buffer from '@ohos.buffer';
export class ResourceManager {
/**
* 获取资源字符串内容
* @param context
* @param filename
* @returns
*/
static getResourcesText(context: Context, filename: string): Promise<string> {
return new Promise<string>((success, error) => {
context.resourceManager.getRawFileContent(filename).then((content: Uint8Array) => {
if (!content) {
error("file is empty");
return
}
let result = buffer.from(content).toString("utf8");
if (result) {
success(result);
} else {
error("parse resources file result is empty");
}
}).catch((err: Error) => {
error(err);
})
})
}
}
\ No newline at end of file
... ...
/**
* StringUtils class.
*/
export class StringUtils {
/**
* Check obj is not empty.
*
* @param {object} obj
* @return {boolean} true(not empty)
*/
static isNotEmpty(obj: any): boolean {
// return (obj && obj !== '');
// 或
return (obj !== undefined && obj !== null && obj !== '');
}
static isEmpty(...params: any): boolean {
if (params.length === 0) {
return true;
}
for (const param of params) {
if (!param) { // param === undefined || param === null || param === '';
return true;
}
}
return false;
}
static formatStringForJS(template: string, ...args: any[]): string {
let formattedString = template;
for (const arg of args) {
formattedString = formattedString.replace(/%s/, arg.toString());
}
return formattedString;
}
static escapeDoubleQuotes(obj:any): any {
if (typeof obj === 'string') {
return obj.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
} else if (typeof obj === 'object') {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
obj[key] = StringUtils.escapeDoubleQuotes(obj[key]);
}
}
}
return obj;
}
}
// export default new StringUtils();
... ...
{
"module": {
"name": "wdJsBridge",
"type": "har",
"description": "$string:shared_desc",
"deviceTypes": [
"phone",
"tablet",
"2in1"
]
}
}
\ No newline at end of file
... ...
{
"color": [
{
"name": "white",
"value": "#FFFFFF"
}
]
}
\ No newline at end of file
... ...
{
"string": [
{
"name": "shared_desc",
"value": "JSBridge是Native(Harmony/Android/iOS)和H5(JavaScript)之间的桥梁,它构建双向通信通道,可以让【Native调用H5】以及让【H5调用Native】,使两者可交互数据。"
}
]
}
\ No newline at end of file
... ...
//notation: js file can only use this kind of comments
//since comments will cause error when use in webview.loadurl,
//comments will be remove by java use regexp
(function() {
if (window.WebViewJavascriptBridge) {
return;
}
var messagingIframe;
var bizMessagingIframe;
var sendMessageQueue = [];
var receiveMessageQueue = [];
var messageHandlers = {};
var CUSTOM_PROTOCOL_SCHEME = 'yy';
var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/';
var responseCallbacks = {};
var uniqueId = 1;
// 创建消息index队列iframe
function _createQueueReadyIframe(doc) {
messagingIframe = doc.createElement('iframe');
messagingIframe.style.display = 'none';
doc.documentElement.appendChild(messagingIframe);
}
//创建消息体队列iframe
function _createQueueReadyIframe4biz(doc) {
bizMessagingIframe = doc.createElement('iframe');
bizMessagingIframe.style.display = 'none';
doc.documentElement.appendChild(bizMessagingIframe);
}
//set default messageHandler 初始化默认的消息线程
function init(messageHandler) {
if (WebViewJavascriptBridge._messageHandler) {
throw new Error('WebViewJavascriptBridge.init called twice');
}
WebViewJavascriptBridge._messageHandler = messageHandler;
var receivedMessages = receiveMessageQueue;
receiveMessageQueue = null;
for (var i = 0; i < receivedMessages.length; i++) {
_dispatchMessageFromNative(receivedMessages[i]);
}
}
// 发送
function send(data, responseCallback) {
_doSend({
data: data
}, responseCallback);
}
// 注册线程 往数组里面添加值
function registerHandler(handlerName, handler) {
messageHandlers[handlerName] = handler;
}
// 调用线程
function callHandler(handlerName, data, responseCallback) {
_doSend({
handlerName: handlerName,
data: data
}, responseCallback);
}
//sendMessage add message, 触发native处理 sendMessage
function _doSend(message, responseCallback) {
if (responseCallback) {
var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime();
responseCallbacks[callbackId] = responseCallback;
message.callbackId = callbackId;
}
sendMessageQueue.push(message);
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
}
// 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容
function _fetchQueue() {
var messageQueueString = JSON.stringify(sendMessageQueue);
sendMessageQueue = [];
//android can't read directly the return data, so we can reload iframe src to communicate with java
if (messageQueueString !== '[]') {
bizMessagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
}
}
//提供给native使用,
function _dispatchMessageFromNative(messageJSON) {
setTimeout(function() {
var message = JSON.parse(messageJSON);
var responseCallback;
//java call finished, now need to call js callback function
if (message.responseId) {
responseCallback = responseCallbacks[message.responseId];
if (!responseCallback) {
return;
}
responseCallback(message.responseData);
delete responseCallbacks[message.responseId];
} else {
//直接发送
if (message.callbackId) {
var callbackResponseId = message.callbackId;
responseCallback = function(responseData) {
_doSend({
responseId: callbackResponseId,
responseData: responseData
});
};
}
var handler = WebViewJavascriptBridge._messageHandler;
if (message.handlerName) {
handler = messageHandlers[message.handlerName];
}
//查找指定handler
try {
handler(message.data, responseCallback);
} catch (exception) {
if (typeof console != 'undefined') {
console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception);
}
}
}
});
}
//提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以
function _handleMessageFromNative(messageJSON) {
//console.log(messageJSON);
if (receiveMessageQueue) {
receiveMessageQueue.push(messageJSON);
}
_dispatchMessageFromNative(messageJSON);
}
var WebViewJavascriptBridge = window.WebViewJavascriptBridge = {
init: init,
send: send,
registerHandler: registerHandler,
callHandler: callHandler,
_fetchQueue: _fetchQueue,
_handleMessageFromNative: _handleMessageFromNative
};
var doc = document;
_createQueueReadyIframe(doc);
_createQueueReadyIframe4biz(doc);
var readyEvent = doc.createEvent('Events');
readyEvent.initEvent('WebViewJavascriptBridgeReady');
readyEvent.bridge = WebViewJavascriptBridge;
doc.dispatchEvent(readyEvent);
})();
... ...
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}
\ No newline at end of file
... ...
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test
\ No newline at end of file
... ...
export { Logger } from './src/main/ets/utils/Logger'
export { ResourcesUtils } from './src/main/ets/utils/ResourcesUtils'
export { StringUtils } from './src/main/ets/utils/StringUtils'
export { AppUtils } from './src/main/ets/utils/AppUtils';
export { BasicDataSource } from './src/main/ets/utils/BasicDataSource';
export { LazyDataSource } from './src/main/ets/utils/LazyDataSource'
export { BreakpointSystem, BreakPointType } from './src/main/ets/utils/BreakPointSystem';
export { ToastUtils } from './src/main/ets/utils/ToastUtils';
export { WindowModel } from './src/main/ets/utils/WindowModel'
export { SPHelper } from './src/main/ets/utils/SPHelper'
export { AccountManagerUtils } from './src/main/ets/utils/AccountManagerUtils'
export { CollectionUtils } from './src/main/ets/utils/CollectionUtils'
export { DateTimeUtils } from './src/main/ets/utils/DateTimeUtils'
export { DeviceUtil } from './src/main/ets/utils/DeviceUtil'
export { DisplayUtils } from './src/main/ets/utils/DisplayUtils'
export { SystemUtils } from './src/main/ets/utils/SystemUtils'
... ...
{
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
],
"targets": [
{
"name": "default"
}
]
}
\ No newline at end of file
... ...
{
"license": "Apache-2.0",
"devDependencies": {},
"author": "",
"name": "wdkit",
"description": "Please describe the basic information.",
"main": "Index.ets",
"version": "1.0.0",
"dependencies": {}
}
... ...
import { StringUtils } from './StringUtils';
import { SPHelper } from './SPHelper';
import { Logger } from './Logger';
const KEY_USER_TOKEN = 'userToken';
const TAG: string = 'AccountManagerUtils';
// 是否已登录hadLogin
let hasLogin: boolean = false;
export class AccountManagerUtils {
// 是否已登录hadLogin
// private static hasLogin: boolean = undefined;
constructor() {
}
static async getUserToken(): Promise<string> {
let userToken = await SPHelper.default.get(KEY_USER_TOKEN, '') as string;
// Logger.info(TAG, 'getUserToken UserToken.' + userToken);
return userToken;
}
static getUserTokenSync(): string {
let userToken = SPHelper.default.getSync(KEY_USER_TOKEN, '') as string;
// Logger.info(TAG, 'getUserToken UserToken.' + userToken);
return userToken;
}
static async putUserToken(value: string) {
await SPHelper.default.save(KEY_USER_TOKEN, value);
}
static putUserTokenSync(value: string) {
SPHelper.default.saveSync(KEY_USER_TOKEN, value);
}
static async deleteUserToken() {
await SPHelper.default.delete(KEY_USER_TOKEN);
}
static deleteUserTokenSync() {
SPHelper.default.deleteSync(KEY_USER_TOKEN);
}
/**
* 是否已登录
* @param folder
* @param files
*/
static async isLogin() {
Logger.info(TAG, 'isLogin hasLogin1:' + hasLogin);
let lastUserToken = await AccountManagerUtils.getUserToken()
Logger.info(TAG, 'isLogin lastUserToken:' + lastUserToken);
if (StringUtils.isEmpty(lastUserToken)) {
hasLogin = false;
Logger.info(TAG, "isLogin lastUserToken is empty");
} else {
hasLogin = true;
Logger.info(TAG, "isLogin lastUserToken is not empty,lastUserToken:" + lastUserToken);
}
// hasLogin = true;
Logger.info(TAG, 'isLogin hasLogin2:' + hasLogin);
return hasLogin;
}
/**
* 是否已登录
* @param folder
* @param files
*/
static isLoginSync() {
Logger.info(TAG, 'isLogin hasLogin1:' + hasLogin);
let lastUserToken = AccountManagerUtils.getUserTokenSync()
Logger.info(TAG, 'isLogin lastUserToken:' + lastUserToken);
if (StringUtils.isEmpty(lastUserToken)) {
hasLogin = false;
Logger.info(TAG, "isLogin lastUserToken is empty");
} else {
hasLogin = true;
Logger.info(TAG, "isLogin lastUserToken is not empty,lastUserToken:" + lastUserToken);
}
// hasLogin = true;
Logger.info(TAG, 'isLogin hasLogin2:' + hasLogin);
return hasLogin;
}
}
// export const accountManagerUtils = new AccountManagerUtils();
\ No newline at end of file
... ...
import bundleManager from '@ohos.bundle.bundleManager';
import common from '@ohos.app.ability.common';
import { Logger } from './Logger';
const TAG: string = 'AppUtils';
/**
* 与应用相关属性或操作
*/
export class AppUtils {
/**
* 获取应用名称
* 即:咪咕视频
*/
static getAppName(context: common.Context): string {
// todo:获取到的是 $string:app_name
// return context.applicationInfo?.label;
return context.resourceManager.getStringByNameSync("app_name");
}
/**
* 获取应用的包名
* 即:com.cmcc.myapplication
*/
static getPackageName(context: common.Context): string {
return context.applicationInfo?.name;
}
/**
* 获取应用版本号,如:1.0.0.0
* @returns 版本号字符串
*/
static getAppVersionName(): string {
try {
let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT)
return bundleInfo?.versionName
} catch (e) {
Logger.warn(TAG, 'get app version error:' + e?.message);
}
return "";
}
/**
* 获取应用版本编码,如:1000000
* @returns 应用版本编码
*/
static getAppVersionCode(): string {
try {
let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT)
return bundleInfo?.versionCode + ""
} catch (e) {
Logger.warn(TAG, 'get app version error:' + e?.message);
}
return '';
}
}
... ...
/**
* IDataSource处理数据侦听器的基本实现
*/
export abstract class BasicDataSource<T> implements IDataSource {
private listeners: DataChangeListener[] = [];
constructor() {
}
// 获取数据总个数
public abstract totalCount(): number;
// 获取索引对应的Item数据
public abstract getData(index: number): T | undefined;
// 注册改变数据的控制器
public registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add DataChangeListener');
this.listeners.push(listener);
}
}
// 注销改变数据的控制器
public unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove DataChangeListener');
this.listeners.splice(pos, 1);
}
}
// 通知控制器数据重新加载数据
public notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
})
}
// 通知控制器数据增加
public notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
})
}
// 通知控制器数据位置变化
public notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to);
})
}
// 通知控制器数据删除
public notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
})
}
// 通知控制器数据变化
public notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
})
}
}
\ No newline at end of file
... ...
import mediaQuery from '@ohos.mediaquery';
import { Logger } from './Logger';
const TAG = 'BreakPointSystem';
interface Breakpoint {
name: string
size: number
mediaQueryListener?: mediaQuery.MediaQueryListener
}
// 响应式布局:"phone","tablet","2in1"
// https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout.md/
declare interface BreakPointTypeOption<T> {
xs: T; // [0, 320) (最小宽度-类型设备) // Wearable/可穿戴设备
sm: T; // [320,600) (小宽度-类型设备) // Phone/折叠设备当前折叠状态为折叠FOLDED/手机(HUAWEI Mate 40 Pro & NOH-AN00)/折叠后345.6vp
md: T; // [600,840) (中等宽度-类型设备) // Fold/折叠设备当前折叠状态为完全展开EXPANDED/折叠手机(HUAWEI Mate X5 & ALT-AL10)/展开后711.68vp
lg: T; // [840,1080) (大宽度-类型设备) // Tablet/2in1(PC与Tablet二合一产品)/TV/Car/PC/laptop
// xl?: T; // [1080,1440) (特大宽度-类型设备) // TV/如4K电视
// xxl?:T; //[1440,+8) (超大宽度-类型设备) // TV/如8K以上(8K/16K)电视
}
export class BreakpointSystem {
// 上次通知的断点
private lastBreakpoint: string = ''
private breakpoints: Breakpoint[] = [
{ name: 'xs', size: 0 },
{ name: 'sm', size: 320 },
{ name: 'md', size: 600 }, // 520vp
{ name: 'lg', size: 840 }
]
private updateCurrentBreakpoint(breakpoint: string): void {
Logger.info(TAG, 'updateCurrentBreakpoint lastBreakpoint: ' + this.lastBreakpoint + ", breakpoint:" + breakpoint)
if (this.lastBreakpoint !== breakpoint) {
this.lastBreakpoint = breakpoint
AppStorage.setOrCreate<string>('currentBreakpoint', breakpoint)
// AppStorage.setOrCreate<string>(BreakpointConstants.CURRENT_BREAKPOINT, this.currentBreakpoint);
Logger.info(TAG, 'on current Breakpoint: ' + this.lastBreakpoint)
}
}
public register() {
this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
let condition: string
if (index === this.breakpoints.length - 1) {
condition = '(' + breakpoint.size + 'vp<=width' + ')'
} else {
condition = '(' + breakpoint.size + 'vp<=width<' + this.breakpoints[index + 1].size + 'vp)'
}
Logger.info(TAG, "register matchMediaSync condition:" + condition);
breakpoint.mediaQueryListener = mediaQuery.matchMediaSync(condition)
breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => {
// Logger.info(TAG, "register change mediaQueryResult:" + JSON.stringify(mediaQueryResult));
if (mediaQueryResult.matches) {
// Logger.info(TAG, "register breakpoint.name:" + JSON.stringify(breakpoint.name));
this.updateCurrentBreakpoint(breakpoint.name)
}
})
})
}
public unregister() {
this.breakpoints.forEach((breakpoint: Breakpoint) => {
if (breakpoint.mediaQueryListener) {
breakpoint.mediaQueryListener.off('change')
}
})
}
}
export class BreakPointType<T> {
options: BreakPointTypeOption<T>
constructor(option: BreakPointTypeOption<T>) {
this.options = option
}
getValue(currentBreakPoint: string): T {
// return this.options[currentBreakPoint] as T;
// Logger.info(TAG, "getValue this.options:" + JSON.stringify(this.options));
if (currentBreakPoint === 'xs') {
return this.options.xs
} else if (currentBreakPoint === 'sm') {
return this.options.sm
} else if (currentBreakPoint === 'md') {
return this.options.md
} else if (currentBreakPoint === 'lg') {
return this.options.lg
// } else if (currentBreakPoint === 'xl') {
// return this.options.xl
// } else if (currentBreakPoint === 'xxl') {
// return this.options.xxl
} else {
// return undefined
return this.options.sm
}
}
}
... ...
import LinkList from '@ohos.util.List';
import HashMap from '@ohos.util.HashMap';
/**
* ArrayUtils class.
*/
export class CollectionUtils {
/**
* The Array utils tag.
*/
private static readonly TAG: string = 'ArrayUtils';
static isArray(value: any): boolean {
if (typeof Array.isArray === 'function') {
return Array.isArray(value);
} else {
return Object.prototype.toString.call(value) === '[object Array]';
}
}
/**
* Check collection is empty or not.
* @param collection any[]
* @returns {boolean} true(empty)
*/
static isEmpty(collection?: any[]): boolean {
return !collection || collection.length === 0;
}
static isEmptyList<T>(list1?: LinkList<T>): boolean {
return !list1 || list1.length === 0;
}
static isEmptyHashMap(obj?: HashMap<any, any>): boolean {
if (!obj) {
return true;
}
return obj.isEmpty();
}
static isEmptyMap(obj?: Map<any, any>): boolean {
if (!obj) {
return true;
}
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
static isEmptyRecord(obj?: Record<string, string>): boolean {
if (!obj) {
return true;
}
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
/**
* Check collection is empty or not.
* @param collection any[]
* @returns {boolean} true(not empty)
*/
static isNotEmpty(collection?: any[]): boolean {
if (!collection) {
return false
}
return collection.length > 0;
}
static getListSize(collection?: any[]): number {
return CollectionUtils.isEmpty(collection) ? 0 : collection.length;
}
static getListElement(collection?: any[], index?: number): any {
if (CollectionUtils.isEmpty(collection) || index === undefined) {
return null;
}
return index >= 0 && index < collection.length ? collection[index] : null;
}
static convertArray<T>(objectList: T[] | T): T[] {
if (CollectionUtils.isArray(objectList)) {
return objectList as T[];
} else {
return [objectList as T];
}
}
/**
* 把list2合入list1后
* @param list1
* @param list2
* @returns
*/
static addAll<T>(list1: LinkList<T>, list2: LinkList<T>): LinkList<T> {
if (!list1) {
list1 = new LinkList<T>();
}
if (!list2) {
return list1;
}
for (let index = 0; index < list2.length; index++) {
list1.add(list2[index])
}
return list1
}
static deepCopy(objectList: any[]): any[] {
const list: any[] = [];
for (const objectItem of objectList) {
if (typeof objectItem !== 'object') {
list.push(objectItem);
continue;
}
if (objectItem.constructor === Date) {
list.push(new Date(objectItem));
continue;
}
if (objectItem.constructor === RegExp) {
list.push(new RegExp(objectItem));
continue;
}
if (objectItem.clone) {
list.push(objectItem.clone());
continue;
}
const newObj = new objectItem.constructor();
for (const key in objectItem) {
if (Object.hasOwnProperty.call(objectItem, key)) {
const val = objectItem[key];
newObj[key] = val;
}
}
list.push(newObj);
}
return list;
}
static deepCopyNumber(values: Set<number>): Set<number> {
const newSet: Set<number> = new Set();
values.forEach((value => {
newSet.add(value);
}));
return newSet;
}
/**
* Uint8Array to string
* @param fileData Uint8Array
*/
static uint8ArrayToString(fileData: Uint8Array): string {
return decodeURIComponent(escape(String.fromCharCode(...fileData)));
}
/**
* string to Uint8Array
* @param str string
*/
static stringToUint8Array(str: string): Uint8Array {
// spilt('') Each character is divided between them
const arr = unescape(encodeURIComponent(str)).split('').map(val => val.charCodeAt(0));
return new Uint8Array(arr);
}
/**
* 截取集合部分数据。
* start:0 - end:20 截取0-19,共20个数据
*/
static getSubElements(collection?: any[], start?: number, end?: number): any[] {
if (CollectionUtils.isEmpty(collection) || start === undefined || end === undefined) {
return null;
}
if (start < 0 || end < start) {
return null;
}
if (end > collection.length) {
return null;
}
let ss = collection.slice(start, end);
ss;
return collection.slice(start, end);
}
}
... ...
import { StringUtils } from './StringUtils';
/**
* 日期/时间工具
*/
// let myDate = new Date();
// myDate.getTime() // 获取以毫秒为单位的时间值。
// myDate.getFullYear(); // 获取完整的年份(4位,1970-????)
// myDate.getMonth(); // 获取myDate月份(0-11,0代表1月)
// myDate.getDate(); // 获取myDate日期(1-31)
// myDate.getDay(); // 获取myDate星期X(0-6,0代表星期天)
// myDate.getTime(); // 获取myDate时间(从1970.1.1开始的毫秒数)
// myDate.getHours(); // 获取myDate小时数(0-23)
// myDate.getMinutes(); // 获取myDate分钟数(0-59)
// myDate.getSeconds(); // 获取myDate秒数(0-59)
// myDate.getMilliseconds(); // 获取myDate毫秒数(0-999)
// myDate.toLocaleDateString(); // 获取当前日期:使用当前或指定的区域设置将日期转换为字符串。
// myDate.toLocaleTimeString(); // 获取当前时间:使用当前或指定的区域设置将时间转换为字符串。
// myDate.toLocaleString(); // 获取日期与时间:使用当前或指定的区域设置将日期和时间转换为字符串
// 日期时间的年月日时分秒以及毫秒的各个字段
// export class DateOpt {
// year: string = ''; // 年 小写y
// month: string = ''; // 月 大写M
// day: string = ''; // 日 小写d
// hour: string = ''; // 时 大写H(24小时制)
// // hh: string = ''; // 时 小写H(12小时制)
// minute: string = ''; // 分 小写m
// second: string = ''; // 秒 小写s
// millisecond: string = ''; // 毫秒 大写S
// }
export class DateTimeUtils {
static readonly MAX_TIME = Math.pow(10, 8) * 24 * 60 * 60 * 1000; // 8640000000000000 毫秒
static readonly MIN_TIME = -DateTimeUtils.MAX_TIME; // -8640000000000000 毫秒
// 日期+时间格式
static readonly PATTERN_DATE_TIME_DEFAULT: string = 'yyyyMMddHHmmss'; // 年月日时分秒
static readonly PATTERN_DATE_TIME_HYPHEN: string = 'yyyy-MM-dd HH:mm:ss'; // 日期中包含连字符/中划线(HYPHEN),时间是以冒号(Colon)分割
static readonly PATTERN_DATE_TIME_HYPHEN_MS: string = 'yyyy-MM-dd HH:mm:ss.SSS'; // 日期中包含连字符/中划线(HYPHEN),时间是以冒号(Colon)分割
static readonly PATTERN_DATE_TIME_SLASH: string = 'yyyy/MM/dd HH:mm:ss'; // 日期中包含正斜杠(forward slash '/')
static readonly PATTERN_DATE_TIME_BACK_SLASH: string = 'yyyy\\MM\\dd HH:mm:ss'; // 日期中包含反斜杠(back slash '\')
static readonly PATTERN_DATE_TIME_DOT: string = 'yyyy.MM.dd HH:mm:ss'; // 日期中包含英文小圆点(DOT '.')
static readonly PATTERN_DATE_TIME_CN: string = 'yyyy年MM月dd日 HH:mm:ss'; // 日期中包含包含中文年月日
static readonly PATTERN_DATE_TIME_MS: string = 'yyyyMMddHHmmssSSS'; // 时间中包含毫秒
static readonly PATTERN_DATE_TIME_WITHOUT_SECOND: string = 'yyyyMMddHHmm'; // 时间中不包含秒
static readonly PATTERN_DATE_TIME_SIMPLIFY: string = 'MM/dd HH:mm'; // 精简的日期+时间(不包含年份和秒), 月/日 时:分
static readonly PATTERN_DATE_SLASH_WITHOUT_YEAR2: string = 'MM-dd'; // 日期中不包含年份
// 仅日期格式(不包含时间)
static readonly PATTERN_DATE_DEFAULT: string = 'yyyyMMdd'; // 年月日
static readonly PATTERN_DATE_HYPHEN: string = 'yyyy-MM-dd'; // 日期中包含连字符/中划线(HYPHEN)
static readonly PATTERN_DATE_SLASH: string = 'yyyy/MM/dd'; // 日期中包含正斜杠(forward slash '/')
static readonly PATTERN_DATE_BACK_SLASH: string = 'yyyy\\MM\\dd'; // 日期中包含反斜杠(back slash '\')
static readonly PATTERN_DATE_DOT: string = 'yyyy.MM.dd'; // 日期中包含英文小圆点(DOT '.')
static readonly PATTERN_DATE_CN: string = 'yyyy年MM月dd日'; // 日期中包含包含中文年月日
static readonly PATTERN_DATE_SLASH_WITHOUT_YEAR: string = 'MM/dd'; // 日期中不包含年份
static readonly PATTERN_DATE_CN_WITHOUT_YEAR: string = 'MM月dd日'; // 日期中不包含年份,且month与day是中文
// 仅时间格式(不包含日期)
static readonly PATTERN_TIME_DEFAULT: string = 'HHmmss'; // 时分秒
static readonly PATTERN_TIME_COLON: string = 'HH:mm:ss'; // 时间是以冒号(Colon)分割
static readonly PATTERN_TIME_MS: string = 'HHmmssSSS'; // 时间中包含毫秒
static readonly PATTERN_TIME_COLON_DOT_MS: string = 'HH:mm:ss.SSS'; // 时间是以冒号(Colon)与点号(DOT)分割,且包含毫秒
static readonly PATTERN_TIME_WITHOUT_SECOND: string = 'HHmm'; // 时间中不包含秒
static readonly PATTERN_TIME_COLON_WITHOUT_SECOND: string = 'HH:mm'; // 时间是以冒号(Colon)分割,且不包含秒
static readonly PATTERN_TIME_COLON_WITHOUT_HOUR: string = 'mm:ss'; // 时间是以冒号(Colon)分割,且不包含小时(分钟长度至少2位,可能是3位)
static readonly PATTERN_WEEK: string = 'E'; // 周几/星期几
static readonly MONTHS_IN_YEAR: number = 12; // 1年12个月
static readonly QUARTERS_IN_YEAR: number = 4; // 1年4个季度
static readonly MONTHS_IN_QUARTER: number = 3; // 1季度3个月
static readonly DAYS_MONTH: number[] = [31, 30, 29, 28]; // 每月多少天:大月(1/3/5/7/8/10/12月);小月(4/6/9/11月);2月(闰年29天/非闰月28天)
static readonly DAYS_IN_WEEK: number = 7; // 1周7天
static readonly HOURS_IN_DAY = 24; // 1天24小时
// 分钟
static readonly MINUTES_IN_HOUR = 60; // 1小时60分(时分秒之间的进制RADIX)
static readonly MINUTES_IN_DAY = 1440 // 60 * 24 // 1天1440分钟
// 秒
static readonly SECONDS_IN_MINUTE = 60; // 1分60秒(时分秒之间的进制RADIX)
static readonly SECONDS_IN_HOUR = 3600 // 60 * 60 // 1小时3600秒
static readonly SECONDS_IN_DAY = 86400 // 60 * 60 * 24 // 1天86400秒
// 毫秒
static readonly MILLISECONDS_IN_SECOND: number = 1000; // 1秒是1000毫秒,秒与毫秒之间的转换进制RADIX
static readonly MILLISECONDS_IN_MINUTE: number = 60000; // 1000 * 60 // 1分钟是60000毫秒
static readonly MILLISECONDS_IN_HOUR: number = 3600000; // 1000 * 60 * 60 // 1小时是3600000毫秒
static readonly MILLISECONDS_IN_DAY: number = 86400000; // 1000 * 60 * 60 * 24 // 1天是86400000毫秒
static readonly CHINESE_YEAR: string = '年';
static readonly CHINESE_MONTH: string = '月';
static readonly CHINESE_DAY: string = '日';
static readonly CHINESE_LAST_WEEK: string = '上周';
static readonly CHINESE_YESTERDAY: string = '昨天';
static readonly CHINESE_TODAY: string = '今天';
static readonly CHINESE_TOMORROW: string = '明天';
static readonly CHINESE_NEXT_WEEK: string = '下周';
// 周x/星期X
static readonly CHINESE_WEEK1: string[] = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
static readonly CHINESE_WEEK2: string[] = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
static readonly ENGLISH_WEEK1 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
static readonly ENGLISH_WEEK2 = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
static readonly ENGLISH_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
/**
* 获取当前日期:年月日
* 返回格式,默认如:yyyyMMdd,20230926
*/
static getCurDate(format = DateTimeUtils.PATTERN_DATE_DEFAULT): string {
const DATETIME = new Date()
return DateTimeUtils.formatDate(DATETIME.getTime(), format)
}
/**
* 获取当前时间:时分秒
* 返回格式,默认如:HHmmss,230559
*/
static getCurTime(format = DateTimeUtils.PATTERN_TIME_DEFAULT): string {
const DATETIME = new Date()
return DateTimeUtils.formatDate(DATETIME.getTime(), format)
}
/**
* 获取当前时间戳,毫秒
* */
public static getTimeStamp(): number {
return new Date().getTime();
}
/**
* 当数字转字符串不足maxLength位时,用前导0补足maxLength位
* @param value-数据值
* @returns
* 年份是4位
* 月/日/时/分/秒,都是2位
* 毫秒是3位
*/
static fill(num: number, maxLength: number = 2): string {
let value: string = '' + num
return value.padStart(maxLength, '0')
}
/**
* 获取两个时间点的时间差
* @param milliseconds1
* @param milliseconds2
* @returns Duration
*/
static getDuration(milliseconds1: number, milliseconds2: number): number {
let date1 = new Date(milliseconds1)
let date2 = new Date(milliseconds2)
let timeDiff = Math.abs(date2.getTime() - date1.getTime());
return timeDiff;
}
/**
* 格式化Duration时间
* @param duration 毫秒
* @returns 返回格式化后的Duration时间
*/
static getFormattedDuration(duration: number): string {
// 也可以直接先除以1000转换为秒后再计算 // duration = duration/1000
// Math.floor 用于向下取整
let hour = Math.floor(duration / (DateTimeUtils.MILLISECONDS_IN_HOUR))
// 用总毫秒数duration减去hour所对应的毫秒数差,再除以每分钟所占用的毫秒数
let minute = Math.floor((duration - hour * (DateTimeUtils.MILLISECONDS_IN_HOUR)) / (DateTimeUtils.MILLISECONDS_IN_MINUTE));
let second = Math.floor(duration / DateTimeUtils.MILLISECONDS_IN_SECOND) % DateTimeUtils.SECONDS_IN_MINUTE; // 先除以1000,转换为秒;再对整分钟取余
if (hour > 0) {
return `${DateTimeUtils.fill(hour)}:${DateTimeUtils.fill(minute)}:${DateTimeUtils.fill(second)}`
}
return `${DateTimeUtils.fill(minute)}:${DateTimeUtils.fill(second)}`
}
/**
* 格式化显示倒计时
* @param milliseconds 时间戳 毫秒
* @returns 返回格式化后的Duration时间
*/
static getDurationToNow(milliseconds: number): string {
let nowDateTime = new Date();
let duration = milliseconds - nowDateTime.getTime();
if (duration < 0) {
duration = 0;
}
return DateTimeUtils.getFormattedDuration(duration)
}
/**
* 根据日期/时间字符串反序列化对应的时间戳
* @param dateTimeString string 日期+时间字符串
* 列举字符串格式,如:
* 20231129,yyyyMMdd
* 20231126230559 yyyyMMddHHmmss
* 20231126230559729 yyyyMMddHHmmssSSS
* 2023-11-26 23:05:59.729, yyyy-MM-dd HH:mm:ss.SSS(先移除所有中划线和冒号及空格等非数字字符)
* 日期/时间字符串中包含连字符/中划线(Hyphen/Strike)/移除冒号(Colon)/移除空白字符(包括空格、制表符、换行符等)/移除正斜杠(forward slash '/')/移除反斜杠(back slash '\')
* @param format:string 日期+时间的格式,默认格式:yyyy-MM-dd
* @param referenceDate:Date 参考日期+时间
* @returns 转换后的时间戳:milliseconds 毫秒
* let dateTimeStr:string = "(预告) 2024年12月24日 02:50 开播"
* let formatPattern:string = "(预告) yyyy年MM月dd日 HH:mm 开播"
* let parsedDate = DateTimeUtils.parseDate(dateTimeStr, formatPattern)
*/
static parseDate(dateTimeString: string, format: string = DateTimeUtils.PATTERN_DATE_HYPHEN, referenceDate?: Date): number {
if (!dateTimeString) {
return 0
}
if (!referenceDate) {
referenceDate = new Date(); // 参考当前时间
}
const optPatternList: string[] = ['y+', 'M+', 'd+', 'H+', 'm+', 's+', 'S+'];
let targetYear: number = 0 // 年
let targetMonth: number = 0 // 月, monthIndex
let targetDay: number = 0 // 日
let targetHour: number = 0 // 时
let targetMinute: number = 0 // 分
let targetSecond: number = 0 // 秒
let targetMillisecond: number = 0 // 毫秒
for (let i = 0; i < optPatternList.length; i++) {
const optPattern = optPatternList[i];
const regExp = new RegExp(optPattern, 'g');
// console.log(optPattern);
let matches = regExp.exec(format);
if (!matches) {
continue
}
// console.dir(matches)
// console.dir(matches?.[0])
// console.dir(matches?.index)
let pick: number = StringUtils.parseNumber(dateTimeString.substring(matches.index, matches.index + matches?.[0].length))
// console.dir(pick)
switch (optPattern) {
case 'y+':
if (pick >= -271821 && pick <= 275760) { // 根据最大日期/时间与根据最小日期/时间计算出的年份范围
targetYear = pick
} else {
targetYear = referenceDate.getFullYear() // 当解析不到年份时,则设置为今年
}
break;
case 'M+': // monthIndex between 0 and 11
if (pick >= 1 && pick <= 12) {
targetMonth = pick - 1
} else {
targetMonth = referenceDate.getMonth() // 当解析不到月份时,则设置为本月
}
break;
case 'd+': // between 1 and 31.
if (pick >= 1 && pick <= 31) {
targetDay = pick
} else {
targetDay = referenceDate.getDate()
}
break;
case 'H+': // from 0 to 23
if (pick >= 0 && pick <= 23) {
targetHour = pick
} else {
targetDay = referenceDate.getDate()
}
break;
case 'm+': // from 0 to 59
if (pick >= 0 && pick <= 59) {
targetMinute = pick
} else {
targetDay = referenceDate.getMinutes()
}
break;
case 's+': // from 0 to 59
if (pick >= 0 && pick <= 59) {
targetSecond = pick
} else {
targetSecond = referenceDate.getSeconds()
}
break;
case 'S+': // from 0 to 999
if (pick >= 0 && pick <= 999) {
targetMillisecond = pick
} else {
targetMillisecond = referenceDate.getMilliseconds()
}
break;
default:
break;
}
}
let targetDate: Date = new Date(targetYear, targetMonth, targetDay, targetHour, targetMinute, targetSecond, targetMillisecond)
return targetDate.getTime()
}
/**
* 把整数时间戳格式化为指定格式的日期+时间字符串
* @param timestamp:毫秒
* @param format 指定要格式化的pattern,默认格式:yyyy-MM-dd
* @returns 格式化后的字符串
* 举例:
* let date_fmt = DateTimeUtils.formatDate(dateTime, "预告 (E) MM月dd日 HH:mm 开播")
*/
static formatDate(timestamp: number, format: string = DateTimeUtils.PATTERN_DATE_HYPHEN): string {
try {
const date = new Date(timestamp);
let targetYear: string = date.getFullYear().toString();
let targetMonth: string = DateTimeUtils.fill(date.getMonth() + 1);
let targetDay: string = DateTimeUtils.fill(date.getDate());
let targetHours: string = DateTimeUtils.fill(date.getHours());
let targetMinutes: string = DateTimeUtils.fill(date.getMinutes());
let targetSeconds: string = DateTimeUtils.fill(date.getSeconds());
let targetMilliseconds: string = DateTimeUtils.fill(date.getMilliseconds(), 3);
let targetDayOfWeek: number = date.getDay();
const dateOptionPatternList: string[] = ['y+', 'M+', 'd+', 'H+', 'm+', 's+', 'S+', 'E'];
for (let i = 0; i < dateOptionPatternList.length; i++) {
const dateOptionPattern = dateOptionPatternList[i];
const dateOptionRegExp = new RegExp(dateOptionPattern);
let match = dateOptionRegExp.exec(format); // 使用 RegExp 的exec 方法在目标字符串中查找匹配项
if (!match) {
continue
}
switch (dateOptionPattern) {
case 'y+':
format = format.replace(dateOptionRegExp, targetYear);
break;
case 'M+':
format = format.replace(dateOptionRegExp, targetMonth);
break;
case 'd+':
format = format.replace(dateOptionRegExp, targetDay);
break;
case 'H+':
format = format.replace(dateOptionRegExp, targetHours);
break;
case 'm+':
format = format.replace(dateOptionRegExp, targetMinutes);
break;
case 's+':
format = format.replace(dateOptionRegExp, targetSeconds);
break;
case 'S+':
format = format.replace(dateOptionRegExp, targetMilliseconds);
break;
case 'E': // from 0 to 6; the day of the week
format = format.replace(dateOptionRegExp, DateTimeUtils.CHINESE_WEEK1[targetDayOfWeek]);
break;
default:
break;
}
}
return format;
} catch (error) {
console.error(`ERROR formatDate error: ${error}.`);
return "";
}
}
/**
* 构造一周中的哪一天/构造星期X/周X
* @param timestamp
* @returns
*/
static buildDayOfWeek(timestamp: number, weeks: string[] = DateTimeUtils.CHINESE_WEEK1): string {
try {
const date = new Date(timestamp);
let day = date.getDay()
let week = weeks[day];
return week ?? ''
} catch (error) {
console.error(`ERROR formatDate error: ${error}.`);
return ''
}
}
static startOfDay(argument: number): Date {
const _date = new Date(argument);
_date.setHours(0, 0, 0, 0);
return _date;
}
static isSameDay(dateLeft: number, dateRight: number): boolean {
const dateLeftStartOfDay = DateTimeUtils.startOfDay(dateLeft);
const dateRightStartOfDay = DateTimeUtils.startOfDay(dateRight);
return dateLeftStartOfDay.getTime() === dateRightStartOfDay.getTime();
}
static addDays(argument: number, amount: number): Date {
const _date = new Date(argument);
if (amount == 0) {
return _date;
}
_date.setDate(_date.getDate() + amount);
return _date;
}
static subDays(date: number, amount: number): Date {
return DateTimeUtils.addDays(date, -amount);
}
static isToday(date: number,): boolean {
return DateTimeUtils.isSameDay(date, Date.now());
}
static isYesterday(date: number): boolean {
return DateTimeUtils.isSameDay(date, DateTimeUtils.subDays(Date.now(), 1).getTime());
}
static isTomorrow(date: number): boolean {
return DateTimeUtils.isSameDay(date, DateTimeUtils.addDays(Date.now(), 1).getTime());
}
// 检查指定的日期是过去的吗?
static isPast(_date: Date): boolean {
return _date.getTime() < Date.now();
}
// 检查指定的日期在未来/将来吗?
static isFuture(_date: Date): boolean {
return _date.getTime() > Date.now();
}
// 检查_date是在dateToCompare之后吗?,如
// const result = isAfter(new Date(1989, 6, 10), new Date(1987, 1, 11))
// => true
static isAfter(_date: Date, dateToCompare: Date): boolean {
return _date.getTime() > dateToCompare.getTime();
}
// 检查_date是在dateToCompare之前吗?,如
// const result = isBefore(new Date(1989, 6, 10), new Date(1987, 1, 11))
// => false
static isBefore(_date: Date, dateToCompare: Date): boolean {
return _date.getTime() < dateToCompare.getTime();
}
/**
* 获取文章发布时间
* */
public static getCommentTime(publishTime: number): string {
let currentTime: number = new Date().getTime();
let timeGap = currentTime - publishTime;
let timeStr = ""
if (timeGap >= 60 * 60 * 1000 * 48) {
let publishYear = new Date(publishTime).getFullYear();
let currentYear = new Date(currentTime).getFullYear();
if (publishYear == currentYear) {
timeStr = this.formatDate(publishTime, DateTimeUtils.PATTERN_DATE_SLASH_WITHOUT_YEAR2)
} else {
timeStr = this.formatDate(publishTime)
}
} else if (timeGap > 60 * 60 * 1000 * 24) {
timeStr = Math.floor(timeGap / (60 * 60 * 1000 * 24)) + "天前";
} else if (timeGap > 60 * 60 * 1000) { // 1小时-24小时
timeStr = Math.floor(timeGap / (60 * 60 * 1000)) + "小时前";
} else if (timeGap > 60 * 1000) { // 1分钟-59分钟
timeStr = Math.floor(timeGap / (60 * 1000)) + "分钟前";
} else { // 1秒钟-59秒钟
timeStr = "刚刚";
}
return timeStr;
}
}
// const dateTimeUtils = new DateTimeUtils()
\ No newline at end of file
... ...
import util from '@ohos.util';
import deviceInfo from '@ohos.deviceInfo';
import { SPHelper } from './SPHelper';
const TAG = 'DeviceUtil';
/**
* 与(硬件)设备相关(不可改变或不可升级)属性或操作
*/
export class DeviceUtil {
static clientId() {
let uuid = SPHelper.default.getSync("clientId", '');
if (uuid == '') {
uuid = util.generateRandomUUID();
SPHelper.default.saveSync("clientId", uuid);
}
return uuid.toString();
}
/**
* 返回设备厂家名称
* HUAWEI
* @returns
*/
static getManufacture(): string {
return deviceInfo.manufacture;
}
/**
* 返回设备品牌名称
* HUAWEI MATE 40 PRO
* @returns
*/
static getBrand(): string {
return deviceInfo.brand;
}
/**
* 返回认证型号
* LIO-AL00
* @returns
*/
static getProductModel(): string {
return deviceInfo.productModel;
}
/**
* 返回产品版本
* OpenHarmony-3.2.6.5(Beta2)
* @returns
*/
static getDisplayVersion(): string {
return deviceInfo.productModel;
}
}
\ No newline at end of file
... ...
import display from '@ohos.display';
import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
import {Logger} from './Logger';
const TAG = 'DisplayUtils';
/**
* 设备显示器/Display属性:
*
手机(HUAWEI Mate 40 Pro & NOH-AN00)-竖屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 0,
"width": 1344, // 屏幕显示的实际宽度/(像素个数/以像素px为单位)
"height": 2772, // 屏幕显示的实际高度/(像素个数/以像素px为单位)
"densityDPI": 560, // 实际像素密度(每英寸像素:120/160/240/320/560)PPI,是一个具体的数值
"orientation": 0,
"densityPixels": 3.5, // 屏幕密度(当像素密度为160时屏幕密度为1.0, 像素比例0.75/1.0/1.5/2.0/3.5) | 缩放因子density = 屏幕像素密度/160, 可用于vp和px转化
"scaledDensity": 3.5, // 可用于fp和px转化
"xDPI": 461.3188781738281,
"yDPI": 457.1999816894531
}
手机(HUAWEI Mate 40 Pro & NOH-AN00)-横屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 1,
"width": 2772,
"height": 1344,
"densityDPI": 560,
"orientation": 1,
"densityPixels": 3.5,
"scaledDensity": 3.5,
"xDPI": 951.47021484375,
"yDPI": 221.67271423339844
}
Fold手机(HUAWEI Mate X5 & ALT-AL10)-折叠状态-竖屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 0,
"width": 1080,
"height": 2504,
"densityDPI": 500,
"orientation": 1,
"densityPixels": 3.125,
"scaledDensity": 3.125,
"xDPI": 173.62025451660156,
"yDPI": 451.0751647949219
}
Fold手机(HUAWEI Mate X5 & ALT-AL10)-折叠状态-横屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 3,
"width": 2504,
"height": 1080,
"densityDPI": 500,
"orientation": 2,
"densityPixels": 3.125,
"scaledDensity": 3.125,
"xDPI": 402.541748046875,
"yDPI": 194.55319213867188
}
Fold手机(HUAWEI Mate X5 & ALT-AL10)-完全展开状态-竖屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 0,
"width": 2224,
"height": 2496,
"densityDPI": 500,
"orientation": 1,
"densityPixels": 3.125,
"scaledDensity": 3.125,
"xDPI": 357.52911376953125,
"yDPI": 449.634033203125
}
平板电脑(HUAWEI MatePad Pro & WGR-W09)(2in1设备)-横屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 60,
"rotation": 0,
"width": 2560,
"height": 1600,
"densityDPI": 240,
"orientation": 1,
"densityPixels": 1.5,
"scaledDensity": 1.5,
"xDPI": 239.05882263183594,
"yDPI": 239.05882263183594
}
*/
/**
* 与显示器/display/screen(硬件)设备相关(不可改变或不可升级)属性或操作(应该读取窗口Window的宽高,而不是显示器display的宽高,因为电脑设备的窗口可以动态调整Window窗口大小)
* 屏幕密度是160时,1vp=1px
*/
export class DisplayUtils {
/**
* Get 屏幕显示/display/screen Width(单位vp)
* 手机(HUAWEI Mate 40 Pro & NOH-AN00)-竖屏:width为1344*3.5=384vp
* 手机(HUAWEI Mate 40 Pro & NOH-AN00)-横屏:width为2772*3.5=792vp
* @returns screen width.
*/
public static getDeviceWidth(): number {
let displayObject: display.Display = display.getDefaultDisplaySync();
// Logger.info(TAG, `getDeviceWidth, displayObject: ${JSON.stringify(displayObject)}`);
let screenWidth = displayObject.width;
let screenDensityDPI = displayObject.densityDPI;
// 像素密度(Pixel Density)
let densityPixels = screenDensityDPI / ConfigurationConstant.ScreenDensity.SCREEN_DENSITY_MDPI
// let densityPixels = displayObject.densityPixels
let deviceWidth = screenWidth / densityPixels;
// Logger.info(TAG, `getDeviceWidth, deviceWidth: ${deviceWidth}`);
return deviceWidth
}
/**
* Get the 显示/display/screen height(单位vp).
*
* @returns screen height.
*/
public static getDeviceHeight(): number {
let displayObject: display.Display = display.getDefaultDisplaySync();
let screenHeight = displayObject.height;
let screenDensityDPI = displayObject.densityDPI;
// 像素密度(Pixel Density)
let densityPixels = screenDensityDPI / ConfigurationConstant.ScreenDensity.SCREEN_DENSITY_MDPI
// let densityPixels = displayObject.densityPixels
let deviceHeight = screenHeight / densityPixels
// Logger.info(TAG, `getDeviceHeight, deviceHeight: ${deviceHeight}`); // 345.6 // 711.68
return deviceHeight
}
}
... ...
import { BasicDataSource } from './BasicDataSource';
/**
* 实现/BasicDataSource抽象类,用于懒数据加载
*/
export class LazyDataSource<T> extends BasicDataSource<T> {
// private dataArray: Array<T> = new Array();
// private dataArray: Array<string> = new Array("0", "1", "2");
// private dataArray: string[] = ["0", "1", "2"];
private dataArray: T[] = [];
constructor() {
super();
// for (let i = 0; i < 100; i++) {
// this.dataArray.push(i)
// }
}
// 获取数据总个数
public totalCount(): number {
return this.dataArray.length;
}
// 获取索引对应的Item数据
public getData(index: number): T {
return this.dataArray[index];
}
// 获取索引对应的Item数据
public get(index: number): T {
return this.getData(index);
}
public getFirst(): T {
return this.getData(0);
}
public getLast(): T {
return this.getData(this.totalCount() - 1);
}
// 获取所有数据
public getDataArray(): T[] {
return this.dataArray;
}
// 增加/插入1个Item/数据,若index为undefined,则在数据尾部增加1个元素;否则,在指定索引(可为负/或大于数组长度)位置插入1个元素
public addItem(item: T, startPosition?: number): void {
if (startPosition == undefined) {
// 将新元素添加到数组的末尾
this.dataArray.push(item);
// this.dataArray.splice(this.dataArray.length, 0, item)
this.notifyDataAdd(this.dataArray.length - 1);
} else {
// 从数组中的index位置开始删除0个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。
// 当index大于等于数组长度时,不删除任何数据,且item加在数组末尾
// 当index为负数时,其代表从数组后向前的索引位置
this.dataArray.splice(startPosition, 0, item);
this.notifyDataAdd(startPosition);
}
}
public addItems(arr: T[], startPosition?: number): void {
if (startPosition == undefined) {
// 将新元素添加到数组的末尾
this.dataArray.push(...arr)
for (let index = this.dataArray.length - arr.length; index < this.dataArray.length; index++) {
this.notifyDataAdd(index);
}
} else {
// 从数组中的position位置开始删除0个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。
// 当index大于等于数组长度时,不删除任何数据,且arr加在数组末尾
// 当index为负数时,其代表从数组后向前的索引位置
this.dataArray.splice(startPosition, 0, ...arr);
for (let index = startPosition; index < arr.length; index++) {
this.notifyDataAdd(index);
}
}
}
// 在数据尾部增加1到多个元素
public push(...items: T[]): void {
this.dataArray.push(...items)
for (let index = this.dataArray.length - items.length; index < this.dataArray.length; index++) {
this.notifyDataAdd(index);
}
}
// 在数据尾部增加一个同类型的LazyDataSource
public pushDataSource(dataSource: LazyDataSource<T>): void {
this.push(...dataSource.dataArray)
}
// 在数据尾部增加1个元素
public addLastItem(item: T): void {
this.addItem(item)
}
// 在数据开头插入1个元素
public addFirstItem(item: T): void {
// 在数组的开头插入(1个或多个)新元素
// this.dataArray.unshift(item)
// this.notifyDataAdd(0);
this.addItem(item, 0)
}
// 在第2个元素位置,插入1个元素
public add2ndItem(item: T): void {
this.addItem(item, 1)
}
// 在第3个元素位置,插入1个元素
public add3rdItem(item: T): void {
this.addItem(item, 2)
}
// 在第4个元素位置,插入1个元素
public add4thItem(item: T): void {
this.addItem(item, 3)
}
// 把from位置的item移动到to位置(暂不支持from/to为负数或大于等于数组长度)
public moveItem(from: number, to: number): void {
// 当from/to大于/等于数组长度时;
if (from >= this.dataArray.length) {
from = this.dataArray.length - 1;
}
if (to >= this.dataArray.length) {
to = this.dataArray.length - 1;
}
// 当from/to为负时;
let remainderFrom = from % this.dataArray.length
if (remainderFrom < 0) {
from = remainderFrom + this.dataArray.length
}
let remainderTo = to % this.dataArray.length
if (remainderTo < 0) {
to = remainderTo + this.dataArray.length
}
// 1.把from位置元素提出暂存
let tempFrom: T = this.dataArray[from];
// 2.把to位置元素覆盖from位置元素,
let tempTo: T = this.dataArray[to];
this.updateItem(tempTo, from)
// 3.把暂存的from位置元素覆盖to位置元素
this.updateItem(tempFrom, to)
this.notifyDataMove(from, to);
}
// 删除index指定索引位置的元素
public deleteItem(index?: number): void {
if (index == undefined) {
// 删除数组的最后1个元素(倒数第1个元素)
// this.dataArray.pop()
this.dataArray.splice(-1, 1)
this.notifyDataDelete(this.dataArray.length);
} else {
// 从数组中的index位置开始,删除1个元素
// 当index大于等于数组长度时,不删除任何数据
// 当index为负数时,其代表从数组后向前的索引位置
this.dataArray.splice(index, 1);
this.notifyDataDelete(index);
}
}
// 删除最后1个元素
public pop(): void {
this.deleteItem()
}
// 删除最后1个元素
public deleteLastItem(): void {
this.deleteItem()
}
// 删除第1个元素
public deleteFirstItem(): void {
this.deleteItem(0)
}
// 删除第1个元素
public delete1stItem(): void {
this.deleteItem(0)
}
// 删除第2个元素
public delete2ndItem(): void {
this.deleteItem(1)
}
// 删除第3个元素
public delete3rdItem(): void {
this.deleteItem(2)
}
// 删除第4个元素
public delete4thItem(): void {
this.deleteItem(3)
}
// 修改/更新index指定索引位置的元素
public updateItem(item: T, index?: number): void {
if (index == undefined || index >= this.dataArray.length) {
// 当不传index或index大于等于数组长度时,修改/更新数组的最后1个元素
this.dataArray.splice(this.dataArray.length - 1, 1, item);
this.notifyDataChange(this.dataArray.length);
} else {
// 从数组中的index位置开始,删除1个元素
// 当index为负数时,其代表从数组后向前的索引位置
this.dataArray.splice(index, 1, item);
this.notifyDataChange(index);
}
}
// 修改/更新最后1个元素
public updateLastItem(item: T): void {
this.updateItem(item)
}
// 修改/更新第1个元素
public updateFirstItem(item: T): void {
this.updateItem(item, 0)
}
// 修改/更新第1个元素
public update2ndItem(item: T): void {
this.updateItem(item, 0)
}
// 修改/更新第2个元素
public update1stItem(item: T): void {
this.updateItem(item, 1)
}
// 修改/更新第3个元素
public update3rdItem(item: T): void {
this.updateItem(item, 2)
}
// 修改/更新第4个元素
public update4thItem(item: T): void {
this.updateItem(item, 3)
}
// 清空数组
public clear(): void {
this.replaceAll()
}
// 把数据全部删除,再添加全部新元素
public replaceAll(...items: T[]): void {
// 从数组中的0位置开始删除dataArray.length个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。
this.dataArray.splice(0, this.dataArray.length, ...items);
this.notifyDataReload()
}
// 获取指定元素的下标
public getIndexOf(element: T): number {
for (let index = 0; index < this.dataArray.length; index++) {
if (this.dataArray[index] == element) {
return index
}
}
return -1
}
public isEmpty(): boolean {
return this.dataArray.length == 0
}
public isNotEmpty(): boolean {
return this.dataArray.length > 0
}
public sort(comparator: (firstValue: T, secondValue: T) => number): void {
this.dataArray.sort(comparator)
}
}
\ No newline at end of file
... ...
import hilog from '@ohos.hilog';
/**
* Log level define
*
* @syscap SystemCapability.HiviewDFX.HiLog
*/
enum LogLevel {
DEBUG = 3,
INFO = 4,
WARN = 5,
ERROR = 6,
FATAL = 7
}
/**
* Common log for all features.
*
* @param {string} prefix Identifies the log tag.
*/
export class Logger {
private static domain: number = 0xFF00;
private static prefix: string = 'SightApp';
private static format: string = `%{public}s, %{public}s`;
/**
* constructor.
*
* @param Prefix Identifies the log tag.
* @param domain Domain Indicates the service domain, which is a hexadecimal integer ranging from 0x0 to 0xFFFFF.
*/
constructor(prefix: string = 'SightApp', domain: number = 0xFF00) {
Logger.prefix = prefix;
Logger.domain = domain;
}
static debug(...args: string[]) {
hilog.debug(Logger.domain, Logger.prefix, Logger.format, args);
}
static info(...args: string[]) {
hilog.info(Logger.domain, Logger.prefix, Logger.format, args);
}
static warn(...args: string[]) {
hilog.warn(Logger.domain, Logger.prefix, Logger.format, args);
}
static error(...args: string[]) {
hilog.error(Logger.domain, Logger.prefix, Logger.format, args);
}
static fatal(...args: string[]) {
hilog.fatal(Logger.domain, Logger.prefix, Logger.format, args);
}
static isLoggable(level: LogLevel) {
hilog.isLoggable(Logger.domain, Logger.prefix, level);
}
}
export default new Logger('SightApp', 0xFF00)
\ No newline at end of file
... ...
import buffer from '@ohos.buffer';
import { BusinessError } from '@ohos.base';
import { Logger } from './Logger';
const TAG = "ResourcesUtils";
// 默认针对entry/src/main/resources/rawfile目录下的文件:
const JSON_FILE_NAME = "agconnect-services.json";
export class ResourcesUtils {
/**
* 获取资源字符串内容
* @param context
* @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json",test.xml,
* @returns text 字符串
*/
static getResourcesText(context: Context, filename: string): Promise<string> {
return new Promise((success, error) => {
Logger.info(TAG, "ResourcesUtils getResourcesText filename:" + filename);
context.resourceManager.getRawFileContent(filename).then((content: Uint8Array) => {
if (!content) {
Logger.warn(TAG, 'getResourcesText then content is empty');
error("file is empty");
return
}
try {
let text = buffer.from(content).toString("utf8");
if (text) {
Logger.info(TAG, "getResourcesText then text:" + text);
success(text);
} else {
Logger.warn(TAG, "getResourcesText then text is empty");
error("resources file text is empty");
}
} catch (err) {
// 转换异常
Logger.error(TAG, `getResourcesText catch err.: ${err}`);
}
}).catch((err: Error) => {
Logger.error(TAG, `getResourcesText getRawFileContent catch, error.name : ${err.name}, error.message:${err.message}`);
error(err);
})
})
}
/**
* 获取资源字符串内容
* @param context
* @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json",test.xml,
* @returns text 字符串
*/
static getResourcesTextSync(context: Context, filename: string): string | null {
Logger.info(TAG, `getResourcesTextSync filename: ${filename}`);
try {
let content: Uint8Array = context.resourceManager.getRawFileContentSync(filename)
if (!content) {
Logger.warn(TAG, 'getResourcesTextSync content is empty');
return null
}
let text = buffer.from(content).toString("utf8");
if (text) {
// Logger.info(TAG, "getRawFileContentSync text:" + text);
} else {
Logger.warn(TAG, "getRawFileContentSync text is empty");
}
return text;
} catch (err) {
// 转换异常
Logger.error(TAG, `getResourcesText catch err.: ${err}`);
return null;
}
}
/**
* 获取资源文件并转为JSON
*
* @param appContext 上下文
* @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json"
* SubscribeListData.json
* @returns JSON Object
*
* 调用方式:
* let compRes: MGHttp.ResponseDTO<BodyComponent> = await ResourcesUtils.getResourcesJson<MGHttp.ResponseDTO<BodyComponent>>(context, 'model/componentList.json');
*/
static getResourcesJson<R>(context: Context, filename: string): Promise<R> {
Logger.info(TAG, `getResourcesJson filename: ${filename}`);
return new Promise<R>((resolve, reject) => {
ResourcesUtils.getResourcesText(context, filename)
.then((text: string) => {
try {
// let config: R = JSON.parse(text)
let config: R = JSON.parse(text) as R;
if (config) {
Logger.info(TAG, "getResourcesJson parse JSON file success.");
// Logger.info(TAG, `getResourcesJson config : ${JSON.stringify(config)}`);
resolve(config);
} else {
reject("getResourcesJson parse JSON file result is empty");
}
} catch (err) {
// json解析异常
Logger.error(TAG, `getResourcesJson catch parse failed.: ${err}`);
reject(err)
}
})
.catch((error: BusinessError) => {
reject(error)
})
})
}
static getResourcesJsonSync<R>(context: Context, filename: string): R | null {
Logger.info(TAG, `getResourcesJsonSync filename: ${filename}`);
let text = ResourcesUtils.getResourcesTextSync(context, filename)
if (!text) {
Logger.warn(TAG, `getResourcesJsonSync file result is empty`);
return null
}
try {
// let config: R = JSON.parse(text)
let config: R = JSON.parse(text) as R;
return config
} catch (err) {
// json解析异常
Logger.error(TAG, `getResourcesJsonSync catch parse failed.: ${err}`);
return null
}
}
}
\ No newline at end of file
... ...
import data_preferences from '@ohos.data.preferences';
/*
// SPHelper.default.get("key1", "defValue1").then((value1) => {
// this.message = value1.toString();
// })
// let value2: string = await SPHelper.default.get("key2", "defValue2");
// this.message = result;
*
* 单例模式
*/
export class SPHelper {
private static context: Context;
private static spFilename: string = '__SPHelper';
static init(context: Context) {
SPHelper.context = context;
}
static setSpFilename(spFilename: string) {
SPHelper.spFilename = spFilename;
}
// 静态属性
static default: SPHelper = new SPHelper();
// 私有构造函数
private constructor() {
}
private async getVideoPreferences(): Promise<data_preferences.Preferences> {
let preferences: data_preferences.Preferences = await data_preferences.getPreferences(SPHelper.context, SPHelper.spFilename);
return preferences;
}
private getVideoPreferencesSync(): data_preferences.Preferences {
let options: data_preferences.Options = { name: SPHelper.spFilename };
let preferences: data_preferences.Preferences = data_preferences.getPreferencesSync(SPHelper.context, options);
return preferences;
}
async save(key: string, value: data_preferences.ValueType) {
const preferences: data_preferences.Preferences = await this.getVideoPreferences();
await preferences.put(key, value)
await preferences.flush()
}
saveSync(key: string, value: data_preferences.ValueType) {
const preferences: data_preferences.Preferences = this.getVideoPreferencesSync();
preferences.putSync(key, value)
preferences.flush() // todo:Asynchronously
}
async get(key: string, defValue: data_preferences.ValueType): Promise<data_preferences.ValueType> {
const preferences: data_preferences.Preferences = await this.getVideoPreferences();
return await preferences.get(key, defValue);
}
getSync(key: string, defValue: data_preferences.ValueType): data_preferences.ValueType {
const preferences: data_preferences.Preferences = this.getVideoPreferencesSync();
return preferences.getSync(key, defValue);
}
async has(key: string): Promise<boolean> {
const preferences: data_preferences.Preferences = await this.getVideoPreferences();
return await preferences.has(key);
}
hasSync(key: string): boolean {
const preferences: data_preferences.Preferences = this.getVideoPreferencesSync();
return preferences.hasSync(key);
}
async delete(key: string) {
const preferences: data_preferences.Preferences = await this.getVideoPreferences();
preferences.delete(key).then(async () => {
await preferences.flush();
}).catch((err: Error) => {
// Logger.error(TAG, 'Failed to delete the key. Cause: ' + err);
});
}
deleteSync(key: string) {
const preferences: data_preferences.Preferences = this.getVideoPreferencesSync();
preferences.deleteSync(key)
preferences.flush(); // todo:Asynchronously
}
async clearSync() {
this.getVideoPreferences().then(async (preferences: data_preferences.Preferences) => {
preferences.clearSync()
await preferences.flush()
}).catch((err: Error) => {
// Logger.error(TAG, 'get the preferences failed, Cause: ' + err);
});
}
// clearSync() {
// let preferences: data_preferences.Preferences = this.getVideoPreferencesSync()
// preferences.clearSync()
// preferences.flush()
// }
}
\ No newline at end of file
... ...
const SLEEP_TIME: number = 10;
/**
* StringUtils class.
*/
export class StringUtils {
/**
* The String utils tag.
*/
private static readonly TAG: string = 'StringUtils';
// 评分-整数或浮点数
private static readonly SCORE_REG_EXP = RegExp(/^(\d+)(\.\d+)?$/);
/**
* Check string is empty.
*
* @param {object} any
* @return {boolean} true(empty)
*/
static isEmpty(...params: any): boolean {
if (params.length === 0) {
return true;
}
for (const param of params) {
if (!param) { // param === undefined || param === null || param === '';
return true;
}
}
return false;
}
/**
* Check obj is not empty.
*
* @param {object} obj
* @return {boolean} true(not empty)
*/
static isNotEmpty(obj: any): boolean {
// return (obj && obj !== '');
// 或
return (obj !== undefined && obj !== null && obj !== '');
}
static isObject(value: any): boolean {
return Object.prototype.toString.call(value) === '[object Object]';
}
static isNotNullObject(value: unknown): boolean {
return value !== null ? typeof value === 'object' : false;
}
static isNullOrUndefined(value: any): boolean {
return value === undefined || value === null;
}
static isFunction(object: any): boolean {
return typeof object === 'function';
}
static isValidObject(objectList: any): boolean {
if (!objectList || typeof objectList !== 'object'
|| objectList.constructor.name === 'Object') {
return false;
}
return true;
}
static isClass(object: any): boolean {
if (StringUtils.isFunction(object)) {
const prototype = object.prototype;
if (!StringUtils.isNotNullObject(prototype)) {
return false;
}
const constructor = prototype.constructor;
if (StringUtils.isFunction(constructor)) {
return true;
}
}
return false;
}
static getClassName(clz: any): string {
if (StringUtils.isNullOrUndefined(clz)) {
return clz;
}
let input = clz;
if (!StringUtils.isClass(input)) {
input = clz.constructor;
}
return input.className ? input.className : input.name;
}
static hash(value: string | number): string {
const str = '' + value;
let hash = 5381;
let index = str.length;
while (index) {
hash = (hash * 33) ^ str.charCodeAt(--index);
}
return '' + (hash >>> 0);
}
static parseNumber(input: string): number {
// let input: string = '135' // 135
// let input: string = '135T' // NaN
// let input: string = 'ytr' // NaN
// let input: string = '' // 0
// let input: string = null // 0
// let input: string = undefined // NaN
const parsedInt = Number(input)
if (!isNaN(parsedInt)) {
return parsedInt
} else {
return 0
}
}
static async sleep(times: number): Promise<void> {
if (!times) {
times = SLEEP_TIME;
}
await new Promise((res) => setTimeout(res, times)) // .then().catch().finally();
}
static isScore(text: string): boolean {
return StringUtils.SCORE_REG_EXP.test(text);
}
}
// export default new StringUtils();
... ...
import deviceInfo from '@ohos.deviceInfo';
/**
* 与鸿蒙系统(软件)设备相关(可改变或可升级)属性或操作
*/
export class SystemUtils {
/**
* 返回AGC格式的系统名称
* OpenHarmony 3.2.6.5(Beta2)
*/
static getOsFullName(): string {
// OpenHarmony-3.2.6.5(Beta2)
let fullName = deviceInfo.osFullName.split('-');
if (fullName && fullName.length >= 1) {
return fullName[0] + ' ' + fullName[1];
}
return '';
}
/**
* 返回系统空闲存储空间,TODO:
* @returns number
*/
static getFreeBytes(): number {
return 0;
}
}
... ...
import prompt from '@ohos.promptAction'
export class ToastUtils {
private static longToastTime: number = 3000
private static shortToastTime: number = 1000
static showToast(message: ResourceStr, duration: number) {
prompt.showToast({ message: message, duration: duration })
}
static shortToast(message: ResourceStr) {
ToastUtils.showToast(message, ToastUtils.shortToastTime)
}
static longToast(message: ResourceStr) {
ToastUtils.showToast(message, ToastUtils.longToastTime)
}
}
// export default new ToastUtils()
\ No newline at end of file
... ...
import window from '@ohos.window';
import { BusinessError } from '@ohos.base';
import deviceInfo from '@ohos.deviceInfo'
import display from '@ohos.display';
export class Size {
width: number = 0
height: number = 0
constructor(width: number, height: number) {
this.width = width;
this.height = height;
}
}
export class WindowModel {
private windowStage?: window.WindowStage;
static shared: WindowModel = new WindowModel()
static TAG = "WindowModel";
setWindowStage(windowStage: window.WindowStage) {
this.windowStage = windowStage;
}
setMainWindowFullScreen(fullScreen: boolean) {
if (deviceInfo.deviceType != "phone") {
return
}
if (this.windowStage === undefined) {
return;
}
this.windowStage.getMainWindow((err, windowClass: window.Window) => {
if (err.code) {
return;
}
windowClass.setWindowLayoutFullScreen(fullScreen, (err) => {
if (err.code) {
return;
}
});
windowClass.setWindowSystemBarEnable(fullScreen ? [] : ['status', 'navigation'], (err) => {
if (err.code) {
return;
}
});
});
}
getWindowSize(): Promise<Size> {
return new Promise((resolve, reject) => {
if (!this.windowStage) {
let dis = display.getDefaultDisplaySync();
reject(new Size(dis.width, dis.height))
return;
}
let rect = this.windowStage.getMainWindowSync().getWindowProperties().windowRect;
resolve(new Size(rect.width, rect.height));
});
}
setWindowKeepScreenOn(isKeepScreenOn: boolean) {
this.windowStage?.getMainWindow((err, windowClass: window.Window) => {
windowClass.setWindowKeepScreenOn(isKeepScreenOn, (err: BusinessError) => {
const errCode: number = err.code;
if (errCode) {
console.error(WindowModel.TAG +'设置屏幕常亮:' + isKeepScreenOn + ',失败: ' + JSON.stringify(err));
return;
}
console.info(WindowModel.TAG +'设置屏幕常亮:' + isKeepScreenOn + ",成功");
})
})
}
/**
* 设置窗口的显示方向属性
* @param orientation
*/
setPreferredOrientation(orientation: window.Orientation): Promise<void> {
return new Promise((resolve, reject) => {
if (!this.windowStage) {
console.error('Failed, the main window is empty');
reject("Failed, the main window is empty")
return;
}
this.windowStage.getMainWindow((err: BusinessError, windowClass: window.Window) => {
if (err.code) {
console.error('Failed to obtain the main window. Cause: ' + err.message);
reject(err)
return;
}
// 2.设置窗口的显示方向属性,使用Promise异步回调。
windowClass.setPreferredOrientation(orientation).then(() => {
console.info('Succeeded in setting the window orientation.');
resolve()
}).catch((err: BusinessError) => {
console.error('Failed to set the window orientation. Cause: ' + err.message);
reject(err)
});
});
})
}
}
... ...
{
"module": {
"name": "wdKit",
"type": "shared",
"description": "$string:shared_desc",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true
}
}
\ No newline at end of file
... ...
{
"color": [
{
"name": "white",
"value": "#FFFFFF"
}
]
}
\ No newline at end of file
... ...
{
"string": [
{
"name": "shared_desc",
"value": "全局工具包"
}
]
}
\ No newline at end of file
... ...
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}
\ No newline at end of file
... ...
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function localUnitTest() {
describe('localUnitTest',() => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
});
});
}
\ No newline at end of file
... ...
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test
\ No newline at end of file
... ...
export { ResponseDTO } from "./src/main/ets/bean/ResponseDTO"
export { HttpRequest as WDHttp } from "./src/main/ets/http/HttpRequest"
export { HttpUrlUtils } from "./src/main/ets/http/HttpUrlUtils"
... ...
{
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
],
"targets": [
{
"name": "default"
}
]
}
\ No newline at end of file
... ...
import { hspTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}
... ...
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope
\ No newline at end of file
... ...
{
"meta": {
"stableOrder": true
},
"lockfileVersion": 3,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"@ohos/axios@^2.1.1": "@ohos/axios@2.1.1",
"wdConstant@../../../../commons/wdConstant": "wdConstant@../wdConstant",
"wdKit@../../../../commons/wdKit": "wdKit@../wdKit"
},
"packages": {
"@ohos/axios@2.1.1": {
"name": "@ohos/axios",
"integrity": "sha512-EQax257+eKKT0Rx7h6N6xvmKbDRWDjCCWOP2vyyktySFwvjtypXuXmQKEvRjmAalR6cqf8mbfhWmpg0bD9OQ3w==",
"resolved": "https://repo.harmonyos.com/ohpm/@ohos/axios/-/axios-2.1.1.har",
"registryType": "ohpm"
},
"wdConstant@../wdConstant": {
"name": "wdconstant",
"resolved": "../wdConstant",
"registryType": "local"
},
"wdKit@../wdKit": {
"name": "wdkit",
"resolved": "../wdKit",
"registryType": "local"
}
}
}
\ No newline at end of file
... ...
... ... @@ -2,16 +2,13 @@
"license": "Apache-2.0",
"devDependencies": {},
"author": "",
"name": "wdcomponent",
"name": "wdnetwork",
"description": "Please describe the basic information.",
"main": "Index.ets",
"version": "1.0.0",
"dependencies": {
"wdConstant": "file:../wdConstant",
"wdKit": "file:../wdKit",
"wdWebComponent": "file:../wdWebComponent",
"wdBean": "file:../wdBean",
"wdRouter": "file:../wdRouter",
"wdNetwork": "file:../wdNetwork"
"@ohos/axios": "^2.1.1"
}
}
... ...
/**
* ResponseDTO
*/
export interface ResponseDTO<T = string> {
success:boolean;
// 服务请求响应值/微服务响应状态码”
code: number;
// 服务请求响应说明
message: string;
// 响应结果
data?: T;
// 请求响应时间戳(unix格式)
timestamp?: number;
}
\ No newline at end of file
... ...
import axios, {
AxiosError,
AxiosInstance,
AxiosResponse,
HttpStatusCode,
InternalAxiosRequestConfig
} from '@ohos/axios';
// import type ResponseDTO from '../models/ResponseDTO';
// const key = 'xxxxyyyyzzz'
// const apiBaseUrl = 'http://127.0.0.1:5566'
// const apiBaseUrl = "https://display-sc.miguvideo.com/display/v3/static";
// console.log("apiBaseUrl:" + apiBaseUrl);
// axios.defaults.baseURL = apiBaseUrl
// 使跨域请求带上cookie等用户认证凭据
// axios.defaults.withCredentials = true;
// 实例化axios
const instance: AxiosInstance = axios.create({
// axios请求基础URL(包括端口号)
// baseURL: apiBaseUrl,
// 单位毫秒
timeout: 15000,
// 跨域请求时,携带cookie等用户认证凭据
// withCredentials: true
});
// 添加请求拦截器
instance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// 在发送请求之前
if (!config.headers["Content-Type"]) {
config.headers["Content-Type"] = "application/json;charset=utf-8";
}
// 公共请求参数
// config.params.key = key
return config;
},
(error: AxiosError) => {
// 请求错误
console.log(`全局请求失败拦截,message:${error.message}`)
return Promise.reject(error);
}
);
// // GET /api/success
// {
// "code": 0,
// "message": "请求成功",
// "data": {
// "name": "管理员"
// }
// }
// // GET /api/fail
// {
// "code": -1,
// "message": "请求失败:XXX错误!",
// "data": null
// }
// 添加响应拦截器
instance.interceptors.response.use(// 响应拦截器response类型就是Axios.request<T = any, R = AxiosResponse<T>, D = any>中的泛型R
// 泛型 T 就是服务器返回数据的类型
// 泛型 R 就是这个泛型 T 数据经过 axios 包装一层得到的 response 对象的类型,而 request 方法的返回值是一个 Promise,其值就是成功态的 R,也就是 response对象。
(response: AxiosResponse) => {
// response为AxiosResponse类型,含有config\data\headers\request\status\statusText属
// console.dir(response)
// 正常响应,可对响应数据做通用处理
// 2xx 范围内的状态码都会触发该函数。
if (response.status === HttpStatusCode.Ok) {
// 直接返回response,当然你也可以只返回response.data
// return response;
// 也可以先解析服务器返回的状态码,可判断code处理通用逻辑
// const { code, message, data } = response.data
// if (code === 0) {
// // 将组件用的数据返回
// return data
// } else {
// // 处理业务错误。
// console.log(`处理业务,message:${message}`)
// return Promise.reject(new Error(message))
// }
// const data: ResponseBean<any> = response.data
// 改造返回的数据,即将AxiosResponse的data返回,服务端返回的数据
return response.data;
} else {
console.log(`httpStatus:${response.status}-${response.status}!`)
// return Promise.reject(error);
return response.data;
}
},
(error: AxiosError) => {
// 异常响应
// console.log('全局响应失败拦截')
// console.log(error.request)
// console.log(error.response)
// 这里用来处理http常见错误,进行全局提示
let message = buildErrorMsg(error.response?.status);
// 错误消息可以使用全局弹框展示出来
console.log(`httpStatus:${error.response?.status}-${message},请检查网络或联系管理员!`)
return Promise.reject(error);
}
);
export default instance;
function buildErrorMsg(httpStatus: number): string {
let message = "";
switch (httpStatus) {
case HttpStatusCode.BadRequest:
message = "请求错误(400)";
break;
case HttpStatusCode.Unauthorized:
message = "未授权(或token 失效),请重新登录(401)";
// 可以触发退出的 action
// 可以做清空storage并跳转到登录页的操作
break;
case HttpStatusCode.Forbidden:
message = "拒绝访问(403)";
break;
case HttpStatusCode.NotFound:
message = "请求出错(404)";
// 请求地址错误
break;
case HttpStatusCode.RequestTimeout:
message = "请求超时(408)";
break;
case HttpStatusCode.InternalServerError:
message = "服务器错误(500)";
// 服务器故障
break;
case HttpStatusCode.NotImplemented:
message = "服务未实现(501)";
break;
case HttpStatusCode.BadGateway:
message = "网络错误(502)";
break;
case HttpStatusCode.ServiceUnavailable:
message = "服务不可用(503)";
break;
case HttpStatusCode.GatewayTimeout:
message = "网络超时(504)";
break;
case HttpStatusCode.HttpVersionNotSupported:
message = "HTTP版本不受支持(505)";
break;
default:
// 网络连接故障
message = `连接出错(${httpStatus})!`;
}
return message;
}
... ...
import ArrayList from '@ohos.util.ArrayList';
import service from './AxiosRequest';
import { HttpUtils } from '../utils/HttpUtils';
import { AxiosError, AxiosHeaders, AxiosRequestConfig, RawAxiosRequestHeaders } from '@ohos/axios';
import { ResponseDTO } from '../bean/ResponseDTO';
import HashMap from '@ohos.util.HashMap';
export class HttpRequest {
private static globalHeaderProviders: ArrayList<() => Record<string, string>> = new ArrayList();
static addGlobalHeaderProvider(provider: () => Record<string, string>) {
HttpRequest.globalHeaderProviders.add(provider)
}
static initHttpHeader() {
HttpRequest.addGlobalHeaderProvider(() => {
return HttpUtils.buildHeaders();
})
}
// 加入泛型限定,返回数据类型为T,
static request<T = ResponseDTO<string>>(config: AxiosRequestConfig): Promise<T> {
return new Promise<T>((resolve, reject) => {
service.request<ResponseDTO<string>, T>(config)
.then((res: T) => {
resolve(res)
})
.catch((err: AxiosError) => {
reject(err)
})
})
// return service.request<any, T>(config)
}
static buildHeaderWithGlobalHeader(headers?: HashMap<string, string>): AxiosHeaders {
let commonHeader: AxiosHeaders = new AxiosHeaders()
headers?.forEach((v, k) => {
commonHeader.set(k, v);
});
HttpRequest.globalHeaderProviders.forEach((func) => {
let headers = func();
for (const obj of Object.entries(headers)) {
commonHeader.set(obj[0], obj[1]);
}
})
if (!commonHeader.get('Content-Type')) {
commonHeader.set('Content-Type', 'application/json;charset=utf-8');
}
return commonHeader
}
static get<T = ResponseDTO<string>>(url: string, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.get(url, config)
}
static post0<T = ResponseDTO<string>>(url: string, data?: object, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.post(url, data, config)
}
static post<T = object>(url: string, data1?: object, headers?: HashMap<string, string>): Promise<T> {
let requestHeaders: AxiosHeaders = new AxiosHeaders()
headers?.forEach((v, k) => {
requestHeaders.set(k, v);
});
let config: AxiosRequestConfig = {
headers: requestHeaders as RawAxiosRequestHeaders,
}
return service.post(url, data1, config)
}
static put<T = ResponseDTO<string>>(url: string, data?: object, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.put(url, data, config)
}
static delete<T = ResponseDTO<string>>(url: string, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.delete(url, config)
}
}
... ...
import HashMap from '@ohos.util.HashMap'
import { ConfigConstants } from 'wdConstant'
import { DateTimeUtils, Logger } from 'wdKit'
/**
* 网络请求业务侧工具类
*/
export class HttpUrlUtils {
/**
* uat环境url
*/
static readonly HOST_UAT: string = "https://pd-apis-uat.pdnews.cn";
/**
* 中文端sit环境
*/
static readonly HOST_SIT: string = "https://pd-apis-sit.pdnews.cn";
/**
* 正式环境url
*/
static readonly HOST_PRODUCT: string = "https://pdapis.pdnews.cn";
/**
* dev环境url
*/
static readonly HOST_DEV: string = "https://pd-apis-dev.pdnews.cn";
/**
* 启动接口(底导接口)
*/
static readonly BOTTOM_NAV_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/bottomNavGroup";
/**
* 展现pageInfo接口
*/
static readonly PAGE_INFO_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/pageInfo";
/**
* 展现comp接口
*/
static readonly COMP_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/compInfo";
/**
* 详情页面详情接口
*/
static readonly DETAIL_PATH: string = "/api/rmrb-bff-display-zh/content/zh/c/content/detail";
/**
* 批查接口,查询互动相关数据,如收藏数、评论数等
*/
static readonly INTERACT_DATA_PATH: string = "/api/rmrb-contact/contact/zh/c/content/interactData";
/**
* 电子报信息
*/
static readonly E_NEWSPAPER_INFO_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/paperApi/paperTime";
/**
* 电子报列表
*/
static readonly E_NEWSPAPER_LIST_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/paperApi/paperList";
private static hostUrl: string = HttpUrlUtils.HOST_PRODUCT;
static getCommonHeaders(): HashMap<string, string> {
let headers: HashMap<string, string> = new HashMap<string, string>()
headers.set('User-Agent', 'Dalvik/2.1.0 (Linux; U; Android 13; 22101317C Build/TKQ1.221013.002)')
headers.set('channel', HttpUrlUtils.getChannel())
//headers.set('appCode', ConfigConstants.appCode)
headers.set('plat', HttpUrlUtils.getPlat())
//headers.set('Authorization', 'APPCODE 83092caa603a421aa0222308b3f6b27a')
headers.set('Content-Type', 'application/json; charset=utf-8')
headers.set('timestamp', HttpUrlUtils.getTimestamp())
headers.set('RMRB-X-TOKEN', HttpUrlUtils.getXToken())
headers.set('device_id', HttpUrlUtils.getDeviceId())
headers.set('cookie', 'RMRB-X-TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc')
headers.set('build_version', HttpUrlUtils.getVersion())
headers.set('adcode', HttpUrlUtils.getAdCode())
headers.set('os_version', HttpUrlUtils.getOsVersion())
//headers.set('X-Ca-Stage', 'PRE')
headers.set('versionCode', HttpUrlUtils.getVersionCode())
headers.set('system', HttpUrlUtils.getTerminalId())
headers.set('version_name', HttpUrlUtils.getVersionName())
headers.set('EagleEye-TraceID', 'D539562E48554A60977AF4BECB6D6C7A')
headers.set('imei', HttpUrlUtils.getImei())
headers.set('Accept-Language', 'zh')
headers.set('city', HttpUrlUtils.getCity())
headers.set('city_dode', HttpUrlUtils.getCityCode())
// TODO 判断是否登录
headers.set('userId', HttpUrlUtils.getUserId())
headers.set('userType', HttpUrlUtils.getUserType())
headers.set('mpassid', 'ZbHTMeTsfaYDAHqt8ZHIzcPs')
HttpUrlUtils.addSpecialHeaders(headers);
// Logger.debug("TAG", '******************* commonHeaders headers start ******************************** ');
// headers.forEach((v,k)=>{
// Logger.debug("TAG", 'getCommonHeaders header: ' + k + ': ' + v);
// })
// Logger.debug("TAG", '******************* commonHeaders headers end ******************************** ');
return headers;
}
static addSpecialHeaders(headers: HashMap<string, string>) {
switch (HttpUrlUtils.hostUrl) {
case HttpUrlUtils.HOST_UAT:
// TODO 待优化到常量类里
headers.set('X-Ca-Stage', 'PRE');
headers.set('Authorization', 'APPCODE 83092caa603a421aa0222308b3f6b27a');
headers.set('appCode', '83092caa603a421aa0222308b3f6b27a');
break
case HttpUrlUtils.HOST_SIT:
headers.set('X-Ca-Stage', 'TEST');
headers.set('Authorization', 'APPCODE 0af1f9085e484c97b2a44704bae72c07');
headers.set('appCode', '0af1f9085e484c97b2a44704bae72c07');
break
case HttpUrlUtils.HOST_PRODUCT:
headers.set('X-Ca-Stage', 'RELEASE');
headers.set('Authorization', 'APPCODE 3d4181bceeb94d9780e10dbb6c67bbf6');
headers.set('appCode', '3d4181bceeb94d9780e10dbb6c67bbf6');
break
case HttpUrlUtils.HOST_DEV:
headers.set('X-Ca-Stage', 'TEST');
headers.set('Authorization', 'APPCODE ff33172859e14f9a8299e3bd769e79f9');
headers.set('appCode', 'ff33172859e14f9a8299e3bd769e79f9');
break
default:
break
}
}
static getHost() {
return HttpUrlUtils.hostUrl;
}
private static getCity() {
// TODO 对接定位
return '%E5%90%88%E8%82%A5%E5%B8%82';
}
private static getChannel() {
// TODO 对接配置
return 'rmrb_china_0000';
}
private static getPlat() {
return 'Phone';
}
private static getTimestamp() {
// return DateTimeUtils.getCurrentTime() + '';
// TODO 暂时写死,有些page 真实时间戳 返回数据为空
return '155203523';
}
private static getXToken() {
return 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc';
}
private static getDeviceId() {
// TODO
return '8a81226a-cabd-3e1b-b630-b51db4a720ed';
}
private static getVersion() {
// TODO
return '202401242103';
}
private static getVersionCode() {
// TODO
return '7301';
}
private static getVersionName() {
// TODO
return '7.3.0.1';
}
private static getAdCode() {
return '340000';
}
private static getOsVersion() {
// TODO
return '12';
}
public static getCityCode() {
// TODO
return '340100';
}
public static getProvinceCode() {
// TODO
return '340000';
}
/**
* 地区code
*/
public static getDistrictCode() {
// TODO
return '340103';
}
private static getTerminalId() {
return 'Android';
}
private static getImei() {
// TODO
return '8a81226a-cabd-3e1b-b630-b51db4a720ed';
}
private static getUserId() {
// TODO 对接登录
return '459776297474949';
}
private static getUserType() {
return '2';
}
}
\ No newline at end of file
... ...
// import { ResponseLogin } from '../bean/account/ResponseLogin';
import { Logger } from 'wdKit';
// import { UserInfo } from '../bean/account/UserInfo';
// import { ConfigConstants } from '../constants/ConfigConstants';
// import { AccountManagerUtils } from './AccountManagerUtils';
// import { AppUtils } from './AppUtils';
// import { DeviceUtil } from './DeviceUtil';
// import { Logger } from './Logger';
// import { StringUtils } from './StringUtils';
const TAG: string = '[HttpUtils]'
export class HttpUtils {
static buildHeaders(): Record<string, string> {
let timestamp: number = new Date().getTime(); // 单位毫秒
// let clientId = DeviceUtil.clientId()
let headers: Record<string, string> = {};
// 通用请求头
headers["version"] = 'V3';
// headers["appId"] = ConfigConstants.appId; // 应用id
// headers["terminalId"] = ConfigConstants.terminalId; // 终端ID
// headers["sourceId"] = ConfigConstants.sourceId; // 咪咕视频
// headers["appType"] = ConfigConstants.appType; // 手机客户端App(安卓)
// headers["clientType"] = ConfigConstants.clientType; // 客户端类型
// headers["appVersion"] = AppUtils.getAppVersionCode() + ''; // 客户端版本号:2600010500
// headers["APP-VERSION-CODE"] = AppUtils.getAppVersionCode() + ''; // APP版本号:250006577
// headers["appVersionName"] = AppUtils.getAppVersionName() // app对外显示版本: '6.1.5.00'
// headers["appCode"] = ConfigConstants.appCode; // 应用编码:产品_渠道_应用的拼接串,用下划线_ 拼接而成
// headers["ptvCode"] = ConfigConstants.ptvCode; // 基线版本号_应用版本号 todo:
// headers["clientProvinceCode"] = ''; // 客户端分省号 // 02
// headers["provinceCode"] = ''; // 客户端分省号 // 02
// headers["clientCityId"] = ''; // 客户端城市ID // 0210
// headers["carrierCode"] = ''; // 运营商信息
// 设备信息请求头
// headers["User-Agent"] = ''; // 终端UA,自动获取
headers["Content-Type"] = 'application/json;charset=UTF-8'; // 返回/响应的HTTP内容类型
headers["os"] = 'android'; // 操作系统类型:鸿蒙、安卓或iOS
// headers["osInfo"] = 'AD'; // 操作系统信息
headers["Phone-Info"] = 'HUAWEI'; // 手机信息: todo
// headers["oaid"] = ''; // 开放匿名设备ID,是中国移动安全联盟(MSA)发起并制定标准用户识别ID
headers["networkInfo"] = 'WIFI'; // 网络类型: todo
headers["cache-control"] = 'no-cache'; // 请求和响应遵循的缓存机制
// headers["clientId"] = clientId; // 客户端编号:客户端初始化时生成的客户端ID,保证唯一性
headers["imei"] = 'd1de6d3ae0db44bea1b3f0e20a14d90a'; // 终端手机序列号: todo
headers["X-UP-CLIENT-CHANNEL-ID"] = '2600010500-99000-101700010130012'; // 客户端渠道ID: todo
headers["channelCode"] = 'VIDEO_APPMAIL'; // 渠道编码
// headers["l_c"] = clientId; // 客户端id,同clientId
// headers["l_t"] = timestamp + ''; // 本机时间戳
// headers["l_s"] = ''; // l_c和l_t拼接后的MD5校验
// 签名相关请求头
headers["timeStamp"] = timestamp + ''; // 服务端时间戳(毫秒):1701667763664
headers["signType"] = 'RSA'; // 签名类型,固定RSA
// 业务请求头
// headers["promotionID"] = '54b0f421-a6df-41d3-9be2-92820b2c5d8c'; // 促销Id todo
// headers["tenantId"] = ''; // 租户Id
// 添加其他header
// headers["sdkCeId"] = '27fb3129-5a54-45bc-8af1-7dc8f1155501'; // 用户中台老接口定义的ID,保持不变,现网:咪咕视频Android版,27fb3129-5a54-45bc-8af1-7dc8f1155501 todo
headers["support-pendant"] = '1'; // 挂件标识, "1":客户端支持挂件节目结构;非"1":不支持挂件节目结构-展示通用对象
Logger.info(TAG, "buildHeader headers:" + JSON.stringify(headers));
return headers;
}
}
// export default new HttpUtils()
... ...
{
"module": {
"name": "wdNetwork",
"type": "shared",
"description": "$string:shared_desc",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
\ No newline at end of file
... ...
{
"color": [
{
"name": "white",
"value": "#FFFFFF"
}
]
}
\ No newline at end of file
... ...
{
"string": [
{
"name": "shared_desc",
"value": "网络库"
}
]
}
\ No newline at end of file
... ...
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}
\ No newline at end of file
... ...
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function localUnitTest() {
describe('localUnitTest',() => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
});
});
}
\ No newline at end of file
... ...
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test
\ No newline at end of file
... ...
export { WDRouterRule } from './src/main/ets/router/WDRouterRule'
export { WDRouterPage } from './src/main/ets/router/WDRouterPage'
export { registerRouter } from './src/main/ets/router/Action2Page'
\ No newline at end of file
... ...
{
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
],
"targets": [
{
"name": "default"
}
]
}
\ No newline at end of file
... ...
import { hspTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}
... ...
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope
\ No newline at end of file
... ...
{
"meta": {
"stableOrder": true
},
"lockfileVersion": 3,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"wdBean@../../../../features/wdBean": "wdBean@../../features/wdBean",
"wdKit@../../../../commons/wdKit": "wdKit@../wdKit"
},
"packages": {
"wdBean@../../features/wdBean": {
"name": "wdbean",
"resolved": "../../features/wdBean",
"registryType": "local"
},
"wdKit@../wdKit": {
"name": "wdkit",
"resolved": "../wdKit",
"registryType": "local"
}
}
}
\ No newline at end of file
... ...
{
"license": "",
"license": "Apache-2.0",
"devDependencies": {},
"author": "",
"name": "entry",
"name": "wdrouter",
"description": "Please describe the basic information.",
"main": "",
"main": "Index.ets",
"version": "1.0.0",
"dependencies": {
"wdComponent": "file:../wdComponent",
"wdConstant": "file:../wdConstant",
"wdKit": "file:../wdKit",
"wdWebComponent": "file:../wdWebComponent",
"wdBean": "file:../wdBean",
"wdRouter": "file:../wdRouter",
"wdNetwork": "file:../wdNetwork"
"wdBean": "file:../../features/wdBean"
}
}
... ...
import ArrayList from '@ohos.util.ArrayList';
import { Action } from 'wdBean'
import { WDRouterPage } from './WDRouterPage'
interface HandleObject {
handle: (action: Action) => (WDRouterPage | undefined)
priority: number
}
export class Action2Page {
private static handles: Record<string, ArrayList<HandleObject>> = {};
static register(actionType: string, handle: (action: Action) => (WDRouterPage | undefined), priority: number = 0) {
let handles = Action2Page.handles[actionType] ?? new ArrayList();
let obj: HandleObject = {
handle: handle,
priority: priority
};
handles.add(obj);
handles.sort((f, s) => {
return f.priority - s.priority;
})
Action2Page.handles[actionType] = handles;
}
static get(action?: Action): WDRouterPage | undefined {
if (!action || !action.type) {
return undefined;
}
let handles = Action2Page.handles[action.type];
if (!handles) {
return undefined;
}
let page: WDRouterPage | undefined
for (let i = 0; i < handles.length; i++) {
let tmp = (handles[i] as HandleObject).handle(action);
if (tmp) {
page = tmp;
break
}
}
return page
}
}
export function registerRouter() {
// Action2Page.register("USER_LOGIN", (action: Action) => {
// return WDRouterPage.webLoginPage
// })
Action2Page.register("JUMP_DETAIL_PAGE", (action: Action) => {
// if (action.params?.detailPageType == 2 || action.params?.detailPageType == 6) {
// return WDRouterPage.detailPlayLivePage
// }
if (action.params?.detailPageType == 7 || action.params?.detailPageType == 8) {
return WDRouterPage.detailPlayShortVideoPage
}
return WDRouterPage.detailPlayVodPage
})
Action2Page.register("JUMP_H5_BY_WEB_VIEW", (action) => {
return WDRouterPage.defaultWebPage
})
Action2Page.register("JUMP_INNER_NEW_PAGE", (action) => {
if (action.params?.pageID == "E_NEWSPAPER") {
return WDRouterPage.eNewspaper
} else if (action.params?.pageID == "MorningEveningPaper"){
return WDRouterPage.morningEveningPaperPage
} else if (action.params?.pageID == "IMAGE_TEXT_DETAIL"){
return WDRouterPage.imageTextDetailPage
}
return undefined
})
}
\ No newline at end of file
... ...
import bundleManager from '@ohos.bundle.bundleManager'
export class WDRouterPage {
private moduleName: string
private pagePath: string
constructor(moduleName: string, pagePath: string) {
this.moduleName = moduleName
this.pagePath = pagePath
}
url() {
let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT)
return `@bundle:${bundleInfo.name}/${this.moduleName}/${this.pagePath}`
}
// 主页
static index = new WDRouterPage("entry", "ets/pages/Index");
// 关于页面
// static aboutPage = new WDRouterPage("entry", "ets/pages/about/AboutPage");
// web默认页面
static defaultWebPage = new WDRouterPage("entry", "ets/pages/web/DefaultWebPage");
// 电子报页面
static eNewspaper = new WDRouterPage("entry", "ets/pages/ENewspaper")
// 早晚报页面
static morningEveningPaperPage = new WDRouterPage("entry", "ets/pages/MorningEveningPaperPage")
// 图文详情页
static imageTextDetailPage = new WDRouterPage("entry", "ets/pages/ImageAndTextDetailPage");
// 短视频详情页
static detailPlayShortVideoPage = new WDRouterPage("wdDetailPlayShortVideo", "ets/pages/DetailPlayShortVideoPage");
// 点播详情页
static detailPlayVodPage = new WDRouterPage("wdDetailPlayVod", "ets/pages/DetailPlayVodPage");
// 直播详情页
static detailPlayLivePage = new WDRouterPage("wdDetailPlayLive", "ets/pages/DetailPlayLivePage");
}
... ...
import router from '@ohos.router'
import { Action } from 'wdBean'
import { ToastUtils } from 'wdKit'
import { Action2Page } from './Action2Page'
import { WDRouterPage } from './WDRouterPage'
export class WDRouterRule {
static jumpWithAction(action?: Action) {
if (!action || !action.type) {
ToastUtils.showToast("跳转参数异常", 1000);
return
}
let page = Action2Page.get(action);
WDRouterRule.jumpWithPage(page, action)
}
private static jumpWithPage(page?: WDRouterPage, params?: object) {
if (page) {
if (params) {
// router.pushUrl({ url: 'pages/routerpage2', , params: params })
router.pushUrl({ url: page.url(), params: params })
} else {
router.pushUrl({ url: page.url() })
}
} else {
ToastUtils.showToast("功能开发中", 1000);
}
}
}
\ No newline at end of file
... ...
{
"module": {
"name": "wdRouter",
"type": "shared",
"description": "$string:shared_desc",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true
}
}
\ No newline at end of file
... ...