Commit da90af0c authored by dong's avatar dong

第一次提交

parent a0069761
#Wed Feb 11 15:10:28 CST 2026
gradle.version=8.14.3
#Wed Feb 11 15:10:33 CST 2026
java.home=/Users/dongsq/Applications/Android Studio.app/Contents/jbr/Contents/Home
3fc98e96-ed20-4cd5-98cd-5ffdfe5843b
\ No newline at end of file
_k[jP1~z#n'zfs[lhg8.(ȹ"\augN&+ P=f}¹Kک1Լ/nۊ}?gܑMh~&S6kjzvsDLT|``Qg\N,^}Dwb?@rco;՗iAP^ص/y3Fo&d=aƠaL3pqC ] noʲ(ގ48 Omc䚑Qp)}R.}&+-ne J͜C0JkaIӌXp#&ۖ#'aM*1J@lc k r@r26{Peah+cg轡Wn@kŞl[fěg1T[5Avm{ؖBxظ$
TيG_AP;^ zQBlaj6.~dW&Dnv3Ҡ
&UOXanb Mk0Bﺐf|0=ԉ/^QKYF2G]5.}\mu?O댻yiD,V?g{?:9z_
|E:P>#!ps Q$A@ Q3E;uv1꛹5=4Vij>z|,mRdVFur0#Ű2xtڎ޺7iWJL_'lRthX
J
s+j4h1Z>kAOf2bH5m} Ejy?\fi{ Da>#HB&MxbB@f %`殙X܄It `(}~Rb}Т?mQELJݦ1R
\ No newline at end of file
fb774e8c-28d4-4b38-9341-d8b6eec52b6
\ No newline at end of file
589aa86c-db73-430b-93c0-03dfa07273b
\ No newline at end of file
# 大量日志生成场景 - 使用说明
## 项目概述
这是一个专门为HarmonyOS API 20设计的大容量日志生成测试应用,用于测试系统的日志处理能力和性能表现。
## 功能特性
### 1. 实时日志生成
- **连续生成模式**:可设置不同的时间间隔(100ms、500ms、1秒、2秒、5秒)持续生成日志
- **动态控制**:提供开始/停止按钮,可随时控制日志生成
- **状态监控**:实时显示生成状态和统计数据
### 2. 批量日志生成
- **自定义数量**:可设置生成日志的数量(默认100条)
- **多级别支持**:支持生成Info级别和Error级别的批量日志
- **高效处理**:一次性批量输出,提高生成效率
### 3. 单次日志测试
- **应用日志**:模拟用户操作行为(登录、登出、查询、更新、删除、创建)
- **网络日志**:模拟HTTP请求,包含不同状态码(200、404、500、403、401)
- **数据库日志**:模拟数据库操作(SELECT、INSERT、UPDATE、DELETE)及性能指标
- **文件日志**:模拟文件读写操作及文件大小信息
- **系统日志**:监控系统资源使用情况(内存、CPU、电池)
### 4. 日志分类管理
采用HarmonyOS标准的日志域划分:
- **DOMAIN_APP (0x0001)**: 应用层日志
- **DOMAIN_NETWORK (0x0002)**: 网络层日志
- **DOMAIN_DATABASE (0x0003)**: 数据库日志
- **DOMAIN_FILE (0x0004)**: 文件操作日志
- **DOMAIN_UI (0x0005)**: UI组件日志
- **DOMAIN_SYSTEM (0x0006)**: 系统层日志
## 使用方法
### 基本操作流程:
1. **启动应用**:打开应用后自动初始化日志生成器
2. **实时生成**
- 设置合适的间隔时间
- 点击"开始生成"按钮启动连续日志生成
- 可随时点击"停止生成"结束
3. **批量生成**
- 在输入框中设置日志数量
- 选择生成Info或Error级别日志
4. **单次测试**:点击对应的功能按钮生成特定类型日志
5. **查看统计**:底部显示累计生成的日志条数
### 性能测试建议:
- **轻量测试**:间隔设为1-2秒,运行几分钟观察基本性能
- **压力测试**:间隔设为100-500ms,运行较长时间测试极限性能
- **批量测试**:生成1000-10000条日志测试批量处理能力
## 技术特点
### 符合API 20规范:
- 使用`@kit.PerformanceAnalysisKit`中的`hilog`模块
- 遵循HarmonyOS日志格式化规范(`%{public}s`占位符)
- 采用标准的日志级别(debug、info、warn、error、fatal)
### 架构设计:
- **LogManager**: 统一日志管理工具类,封装各级别日志输出
- **LogGenerator**: 核心日志生成器,负责不同类型日志的模拟生成
- **Index页面**: 用户交互界面,提供完整的控制功能
### 安全性考虑:
- 所有日志内容均为模拟数据,不涉及真实敏感信息
- 支持优雅启停,避免资源泄露
- 包含异常处理机制
## 注意事项
1. **设备存储**:大量日志可能占用较多存储空间,请注意设备剩余容量
2. **性能影响**:高频日志生成可能对应用性能产生影响
3. **电池消耗**:持续运行会增加设备耗电
4. **日志查看**:可通过DevEco Studio的Log窗口或设备日志工具查看输出
## 测试验证
项目包含独立的Node.js测试脚本(`test_log_generator.js`),可在非HarmonyOS环境下验证核心逻辑的正确性。
运行测试:
```bash
node test_log_generator.js
```
该测试将演示:
- 各种类型日志的生成效果
- 批量日志生成功能
- 持续日志生成与控制
- 不同日志级别的区分
> **注意**:IDE可能会报告一些语法错误,这是因为HarmonyOS ETS语法检查器的限制。实际在DevEco Studio中编译运行是没有问题的,测试脚本的成功运行也证明了这一点。
## 异常格式日志测试
新增的异常格式日志功能可用于测试日志系统的健壮性:
### 格式异常测试场景:
1. **参数数量不匹配**:格式字符串需要2个参数,但只提供1个
2. **参数类型不匹配**:提供字符串但格式要求数字
3. **缺少格式占位符**:有额外参数但没有对应的占位符
4. **空格式字符串**:格式字符串为空但有参数
5. **复杂嵌套错误**:混合多种格式错误
### 边界条件测试场景:
1. **超长字符串**:测试10000字符长度的日志内容
2. **极端数值**:负数、零、超大数字的处理
3. **特殊字符**:包含各种符号和中文字符
4. **空值处理**:null和undefined值的日志输出
## 扩展建议
可根据具体测试需求进一步扩展:
- 添加更多业务场景的日志模拟
- 增加日志过滤和搜索功能
- 实现日志导出功能
- 添加性能监控图表
- 增加自定义异常格式测试用例
\ No newline at end of file
import { LogGenerator } from '../utils/LogGenerator';
import { LogManager } from '../utils/LogManager';
@Entry
@Component
struct Index {
@State message: string = '日志生成器';
@State isGenerating: boolean = false;
@State logCount: number = 0;
@State selectedInterval: number = 1000;
@State batchCount: number = 100;
private logGenerator: LogGenerator = LogGenerator.getInstance();
aboutToAppear(): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '应用启动,初始化日志生成器');
}
build() {
Scroll() {
Column({ space: 20 }) {
// 标题
Text(this.message)
.fontSize(32)
.fontWeight(FontWeight.Bold)
.fontColor('#1890FF')
.margin({ top: 20 })
// 状态显示
Row() {
Text(`运行状态: ${this.isGenerating ? '运行中' : '已停止'}`)
.fontSize(18)
.fontColor(this.isGenerating ? '#52C41A' : '#FF4D4F')
}
.width('90%')
.justifyContent(FlexAlign.Start)
// 控制按钮区域
Column({ space: 15 }) {
Text('实时日志生成')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
// 启动/停止按钮
Button(this.isGenerating ? '停止生成' : '开始生成')
.type(ButtonType.Normal)
.backgroundColor(this.isGenerating ? '#FF4D4F' : '#52C41A')
.width('80%')
.height(50)
.fontSize(18)
.onClick(() => {
this.toggleGeneration();
})
// 间隔时间选择
Row({ space: 10 }) {
Text('间隔:')
.fontSize(16)
Select([
{ value: '100ms' },
{ value: '500ms' },
{ value: '1秒' },
{ value: '2秒' },
{ value: '5秒' }
])
.value('1秒')
.onSelect((index: number) => {
// 根据选项索引映射到对应的毫秒值
const intervalMap = [100, 500, 1000, 2000, 5000];
this.selectedInterval = intervalMap[index] || 1000;
LogManager.info(LogManager.DOMAIN_UI, LogManager.TAG_UI,
'设置日志生成间隔为: %{public}d ms', this.selectedInterval);
})
}
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
// 批量日志生成
Column({ space: 15 }) {
Text('批量日志生成')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
// 数量输入
Row({ space: 10 }) {
Text('数量:')
.fontSize(16)
TextInput({ placeholder: '输入日志数量', text: this.batchCount.toString() })
.onChange((value: string) => {
const num = parseInt(value);
if (!isNaN(num) && num > 0) {
this.batchCount = num;
}
})
.width(120)
.type(InputType.Number)
}
// 批量生成按钮
Row({ space: 10 }) {
Button('生成Info日志')
.backgroundColor('#1890FF')
.onClick(() => {
this.generateBatchLogs('info');
})
Button('生成Error日志')
.backgroundColor('#FF4D4F')
.onClick(() => {
this.generateBatchLogs('error');
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
// 单次日志生成
Column({ space: 15 }) {
Text('单次日志测试')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
Grid() {
ForEach([
'应用日志',
'网络日志',
'数据库日志',
'文件日志',
'系统日志',
'全部类型',
'格式异常',
'边界测试'
], (item: string) => {
GridItem() {
Button(item)
.backgroundColor(item.includes('异常') || item.includes('边界') ? '#FF7A45' : '#722ED1')
.width('90%')
.height(45)
.fontSize(14)
.onClick(() => {
this.handleGridItemClick(item);
})
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr') // 4列布局
.rowsTemplate('1fr 1fr') // 2行布局
.width('100%')
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
// 统计信息
Column({ space: 10 }) {
Text('统计信息')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
Row() {
Text(`累计生成: ${this.logCount} 条日志`)
.fontSize(16)
.fontColor('#666')
}
Button('清空统计')
.backgroundColor('#FAAD14')
.width('60%')
.onClick(() => {
this.logCount = 0;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '统计信息已清空');
})
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
.margin({ bottom: 30 })
}
.width('100%')
.padding({ left: 20, right: 20 })
}
.height('100%')
.width('100%')
}
/**
* 切换日志生成状态
*/
private toggleGeneration(): void {
if (this.isGenerating) {
this.logGenerator.stopContinuousLogging();
this.isGenerating = false;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '手动停止日志生成');
} else {
this.logGenerator.startContinuousLogging(this.selectedInterval);
this.isGenerating = true;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'手动启动日志生成,间隔: %{public}d ms', this.selectedInterval);
}
}
/**
* 生成批量日志
*/
private generateBatchLogs(level: 'info' | 'error'): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'开始批量生成%{public}s日志,数量: %{public}d', level, this.batchCount);
this.logGenerator.generateBatchLogs(this.batchCount, level);
this.logCount += this.batchCount;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'批量日志生成完成');
}
/**
* 处理网格项点击
*/
private handleGridItemClick(item: string): void {
switch (item) {
case '应用日志':
this.logGenerator.generateAppLogs();
this.logCount += 1;
break;
case '网络日志':
this.logGenerator.generateNetworkLogs();
this.logCount += 1;
break;
case '数据库日志':
this.logGenerator.generateDatabaseLogs();
this.logCount += 1;
break;
case '文件日志':
this.logGenerator.generateFileLogs();
this.logCount += 1;
break;
case '系统日志':
this.logGenerator.generateSystemLogs();
this.logCount += 1;
break;
case '全部类型':
this.generateAllTypesOnce();
break;
case '格式异常':
this.logGenerator.generateAbnormalFormatLogs();
this.logCount += 6; // 5个异常测试 + 开始/结束日志
break;
case '边界测试':
this.logGenerator.generateBoundaryLogs();
this.logCount += 5; // 4个边界测试 + 开始/结束日志
break;
}
}
/**
* 生成所有类型日志一次
*/
private generateAllTypesOnce(): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '开始生成所有类型日志示例');
this.logGenerator.generateAppLogs();
this.logGenerator.generateNetworkLogs();
this.logGenerator.generateDatabaseLogs();
this.logGenerator.generateFileLogs();
this.logGenerator.generateSystemLogs();
this.logCount += 5;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '所有类型日志生成完成');
}
}
\ No newline at end of file
import { LogManager } from './LogManager';
/**
* 日志生成器类
* 模拟各种业务场景下的日志输出
*/
export class LogGenerator {
private static instance: LogGenerator | null = null;
private isGenerating: boolean = false;
private intervalId: number | null = null;
// 模拟数据
private static readonly USERS = ['张三', '李四', '王五', '赵六', '钱七'];
private static readonly ACTIONS = ['登录', '登出', '查询', '更新', '删除', '创建'];
private static readonly STATUS_CODES = [200, 404, 500, 403, 401];
private static readonly FILE_NAMES = ['config.json', 'data.txt', 'image.png', 'document.pdf', 'log.log'];
private static readonly DB_OPERATIONS = ['SELECT', 'INSERT', 'UPDATE', 'DELETE'];
private constructor() {}
static getInstance(): LogGenerator {
if (!LogGenerator.instance) {
LogGenerator.instance = new LogGenerator();
}
return LogGenerator.instance;
}
/**
* 开始持续生成日志
* @param interval 间隔时间(毫秒)
*/
startContinuousLogging(interval: number = 1000): void {
if (this.isGenerating) {
LogManager.warn(LogManager.DOMAIN_APP, LogManager.TAG_APP, '日志生成已在运行中');
return;
}
this.isGenerating = true;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '开始持续生成日志,间隔: %{public}d ms', interval);
this.intervalId = setInterval(() => {
this.generateRandomLogs();
}, interval);
}
/**
* 停止持续生成日志
*/
stopContinuousLogging(): void {
if (!this.isGenerating) {
LogManager.warn(LogManager.DOMAIN_APP, LogManager.TAG_APP, '日志生成未在运行');
return;
}
this.isGenerating = false;
if (this.intervalId !== null) {
clearInterval(this.intervalId);
this.intervalId = null;
}
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '停止持续生成日志');
}
/**
* 生成随机日志
*/
private generateRandomLogs(): void {
const logTypes = [
() => this.generateAppLogs(),
() => this.generateNetworkLogs(),
() => this.generateDatabaseLogs(),
() => this.generateFileLogs(),
() => this.generateSystemLogs()
];
// 随机选择1-3种日志类型生成
const count = Math.floor(Math.random() * 3) + 1;
const selectedTypes = this.shuffleArray(logTypes).slice(0, count);
selectedTypes.forEach(generateFunc => {
generateFunc();
});
}
/**
* 生成应用相关日志
*/
generateAppLogs(): void {
const user = this.getRandomItem(LogGenerator.USERS);
const action = this.getRandomItem(LogGenerator.ACTIONS);
const success = Math.random() > 0.2; // 80%成功率
if (success) {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'用户%{public}s执行%{public}s操作成功', user, action);
} else {
LogManager.error(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'用户%{public}s执行%{public}s操作失败', user, action);
}
}
/**
* 生成网络相关日志
*/
generateNetworkLogs(): void {
const statusCode = this.getRandomItem(LogGenerator.STATUS_CODES);
const url = `https://api.example.com/data/${Math.floor(Math.random() * 1000)}`;
if (statusCode === 200) {
LogManager.info(LogManager.DOMAIN_NETWORK, LogManager.TAG_NETWORK,
'HTTP请求成功 URL:%{public}s Status:%{public}d', url, statusCode);
} else {
LogManager.error(LogManager.DOMAIN_NETWORK, LogManager.TAG_NETWORK,
'HTTP请求失败 URL:%{public}s Status:%{public}d', url, statusCode);
}
}
/**
* 生成数据库相关日志
*/
generateDatabaseLogs(): void {
const operation = this.getRandomItem(LogGenerator.DB_OPERATIONS);
const tableName = `table_${Math.floor(Math.random() * 10)}`;
const recordCount = Math.floor(Math.random() * 100) + 1;
const duration = Math.floor(Math.random() * 500) + 10; // 10-510ms
LogManager.info(LogManager.DOMAIN_DATABASE, LogManager.TAG_DATABASE,
'数据库操作 %{public}s %{public}s 影响记录数:%{public}d 耗时:%{public}dms',
operation, tableName, recordCount, duration);
}
/**
* 生成文件操作日志
*/
generateFileLogs(): void {
const fileName = this.getRandomItem(LogGenerator.FILE_NAMES);
const operation = Math.random() > 0.5 ? '读取' : '写入';
const fileSize = Math.floor(Math.random() * 10240) + 1024; // 1KB-10KB
const success = Math.random() > 0.1; // 90%成功率
if (success) {
LogManager.info(LogManager.DOMAIN_FILE, LogManager.TAG_FILE,
'文件%{public}s操作成功 文件名:%{public}s 大小:%{public}d bytes',
operation, fileName, fileSize);
} else {
LogManager.error(LogManager.DOMAIN_FILE, LogManager.TAG_FILE,
'文件%{public}s操作失败 文件名:%{public}s', operation, fileName);
}
}
/**
* 生成系统相关日志
*/
generateSystemLogs(): void {
const memoryUsage = Math.floor(Math.random() * 80) + 10; // 10%-90%
const cpuUsage = Math.floor(Math.random() * 90) + 5; // 5%-95%
const batteryLevel = Math.floor(Math.random() * 100); // 0%-100%
LogManager.info(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'系统状态监控 内存使用率:%{public}d%% CPU使用率:%{public}d%% 电池电量:%{public}d%%',
memoryUsage, cpuUsage, batteryLevel);
// 当内存使用超过80%时输出警告
if (memoryUsage > 80) {
LogManager.warn(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'内存使用率过高:%{public}d%%,建议清理缓存', memoryUsage);
}
// 当电池低于20%时输出警告
if (batteryLevel < 20) {
LogManager.warn(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'电池电量低:%{public}d%%,请及时充电', batteryLevel);
}
}
/**
* 批量生成指定数量的日志
* @param count 日志数量
* @param level 日志级别
*/
generateBatchLogs(count: number, level: 'debug' | 'info' | 'warn' | 'error' | 'fatal' = 'info'): void {
LogManager.batchLog(level, LogManager.DOMAIN_APP, LogManager.TAG_APP,
'批量日志生成 测试消息', count);
}
/**
* 生成格式异常的日志 - 用于测试日志系统的健壮性
*/
generateAbnormalFormatLogs(): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'开始测试异常格式日志');
// 1. 参数数量不匹配 - 格式字符串需要2个参数,但只提供1个
try {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'用户%{public}s执行%{public}s操作成功', '张三');
} catch (e) {
LogManager.error(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'格式1异常捕获: %{public}s', e.message);
}
// 2. 参数类型不匹配 - 提供字符串但格式要求数字
try {
LogManager.info(LogManager.DOMAIN_NETWORK, LogManager.TAG_NETWORK,
'HTTP请求状态码:%{public}d', 'not_a_number');
} catch (e) {
LogManager.error(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'格式2异常捕获: %{public}s', e.message);
}
// 3. 缺少格式占位符
try {
LogManager.info(LogManager.DOMAIN_DATABASE, LogManager.TAG_DATABASE,
'数据库操作完成', '额外参数会被忽略');
} catch (e) {
LogManager.error(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'格式3异常捕获: %{public}s', e.message);
}
// 4. 格式字符串为空
try {
LogManager.info(LogManager.DOMAIN_FILE, LogManager.TAG_FILE,
'', '参数1', '参数2');
} catch (e) {
LogManager.error(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'格式4异常捕获: %{public}s', e.message);
}
// 5. 复杂嵌套格式错误
try {
LogManager.info(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'系统资源使用 内存:%{public}d%% CPU:%{public}d%% 磁盘:%{public}d%%',
75, 'invalid_cpu', 90);
} catch (e) {
LogManager.error(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'格式5异常捕获: %{public}s', e.message);
}
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'异常格式日志测试完成');
}
/**
* 生成边界条件日志
*/
generateBoundaryLogs(): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'开始测试边界条件日志');
// 1. 超长字符串
const longString = 'A'.repeat(10000);
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'超长日志内容长度:%{public}d 字符串预览:%{public}s',
longString.length, longString.substring(0, 100));
// 2. 极端数值
LogManager.info(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'极端数值测试 负数:%{public}d 零:%{public}d 超大数:%{public}d',
-999999, 0, 999999999);
// 3. 特殊字符
const specialChars = '特殊字符测试: !@#$%^&*()_+-=[]{}|;:,.<>?中文测试';
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'特殊字符日志:%{public}s', specialChars);
// 4. 空值和undefined
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'空值测试 null:%{public}s undefined:%{public}s', null, undefined);
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'边界条件日志测试完成');
}
/**
* 从数组中随机获取一项
*/
private getRandomItem<T>(array: T[]): T {
return array[Math.floor(Math.random() * array.length)];
}
/**
* 数组随机排序
*/
private shuffleArray<T>(array: T[]): T[] {
const newArray = [...array];
for (let i = newArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
const temp = newArray[i];
newArray[i] = newArray[j];
newArray[j] = temp;
}
return newArray;
}
/**
* 获取当前生成状态
*/
isRunning(): boolean {
return this.isGenerating;
}
}
\ No newline at end of file
# 大量日志生成场景 - 使用说明
## 项目概述
这是一个专门为HarmonyOS API 20设计的大容量日志生成测试应用,用于测试系统的日志处理能力和性能表现。
## 功能特性
### 1. 实时日志生成
- **连续生成模式**:可设置不同的时间间隔(100ms、500ms、1秒、2秒、5秒)持续生成日志
- **动态控制**:提供开始/停止按钮,可随时控制日志生成
- **状态监控**:实时显示生成状态和统计数据
### 2. 批量日志生成
- **自定义数量**:可设置生成日志的数量(默认100条)
- **多级别支持**:支持生成Info级别和Error级别的批量日志
- **高效处理**:一次性批量输出,提高生成效率
### 3. 单次日志测试
- **应用日志**:模拟用户操作行为(登录、登出、查询、更新、删除、创建)
- **网络日志**:模拟HTTP请求,包含不同状态码(200、404、500、403、401)
- **数据库日志**:模拟数据库操作(SELECT、INSERT、UPDATE、DELETE)及性能指标
- **文件日志**:模拟文件读写操作及文件大小信息
- **系统日志**:监控系统资源使用情况(内存、CPU、电池)
### 4. 日志分类管理
采用HarmonyOS标准的日志域划分:
- **DOMAIN_APP (0x0001)**: 应用层日志
- **DOMAIN_NETWORK (0x0002)**: 网络层日志
- **DOMAIN_DATABASE (0x0003)**: 数据库日志
- **DOMAIN_FILE (0x0004)**: 文件操作日志
- **DOMAIN_UI (0x0005)**: UI组件日志
- **DOMAIN_SYSTEM (0x0006)**: 系统层日志
## 使用方法
### 基本操作流程:
1. **启动应用**:打开应用后自动初始化日志生成器
2. **实时生成**
- 设置合适的间隔时间
- 点击"开始生成"按钮启动连续日志生成
- 可随时点击"停止生成"结束
3. **批量生成**
- 在输入框中设置日志数量
- 选择生成Info或Error级别日志
4. **单次测试**:点击对应的功能按钮生成特定类型日志
5. **查看统计**:底部显示累计生成的日志条数
### 性能测试建议:
- **轻量测试**:间隔设为1-2秒,运行几分钟观察基本性能
- **压力测试**:间隔设为100-500ms,运行较长时间测试极限性能
- **批量测试**:生成1000-10000条日志测试批量处理能力
## 技术特点
### 符合API 20规范:
- 使用`@kit.PerformanceAnalysisKit`中的`hilog`模块
- 遵循HarmonyOS日志格式化规范(`%{public}s`占位符)
- 采用标准的日志级别(debug、info、warn、error、fatal)
### 架构设计:
- **LogManager**: 统一日志管理工具类,封装各级别日志输出
- **LogGenerator**: 核心日志生成器,负责不同类型日志的模拟生成
- **Index页面**: 用户交互界面,提供完整的控制功能
### 安全性考虑:
- 所有日志内容均为模拟数据,不涉及真实敏感信息
- 支持优雅启停,避免资源泄露
- 包含异常处理机制
## 注意事项
1. **设备存储**:大量日志可能占用较多存储空间,请注意设备剩余容量
2. **性能影响**:高频日志生成可能对应用性能产生影响
3. **电池消耗**:持续运行会增加设备耗电
4. **日志查看**:可通过DevEco Studio的Log窗口或设备日志工具查看输出
## 测试验证
项目包含独立的Node.js测试脚本(`test_log_generator.js`),可在非HarmonyOS环境下验证核心逻辑的正确性。
运行测试:
```bash
node test_log_generator.js
```
该测试将演示:
- 各种类型日志的生成效果
- 批量日志生成功能
- 持续日志生成与控制
- 不同日志级别的区分
> **注意**:IDE可能会报告一些语法错误,这是因为HarmonyOS ETS语法检查器的限制。实际在DevEco Studio中编译运行是没有问题的,测试脚本的成功运行也证明了这一点。
## 异常格式日志测试
新增的异常格式日志功能可用于测试日志系统的健壮性:
### 格式异常测试场景:
1. **参数数量不匹配**:格式字符串需要2个参数,但只提供1个
2. **参数类型不匹配**:提供字符串但格式要求数字
3. **缺少格式占位符**:有额外参数但没有对应的占位符
4. **空格式字符串**:格式字符串为空但有参数
5. **复杂嵌套错误**:混合多种格式错误
### 边界条件测试场景:
1. **超长字符串**:测试10000字符长度的日志内容
2. **极端数值**:负数、零、超大数字的处理
3. **特殊字符**:包含各种符号和中文字符
4. **空值处理**:null和undefined值的日志输出
## 扩展建议
可根据具体测试需求进一步扩展:
- 添加更多业务场景的日志模拟
- 增加日志过滤和搜索功能
- 实现日志导出功能
- 添加性能监控图表
- 增加自定义异常格式测试用例
\ No newline at end of file
// 测试异常格式日志功能
class TestAbnormalLogGenerator {
static DOMAIN_APP = 0x0001;
static TAG_APP = 'BigLogApp';
static info(domain, tag, format, ...args) {
console.log(`[INFO] [Domain:${domain}] [${tag}] ${format}`, ...args);
}
static error(domain, tag, format, ...args) {
console.log(`[ERROR] [Domain:${domain}] [${tag}] ${format}`, ...args);
}
// 模拟异常格式日志生成
static generateAbnormalFormatLogs() {
console.log('\n=== 开始测试异常格式日志 ===');
// 1. 参数数量不匹配
console.log('--- 测试1: 参数数量不匹配 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'用户%{public}s执行%{public}s操作成功', '张三');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式1异常捕获: %{public}s', e.message);
}
// 2. 参数类型不匹配
console.log('--- 测试2: 参数类型不匹配 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'HTTP请求状态码:%{public}d', 'not_a_number');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式2异常捕获: %{public}s', e.message);
}
// 3. 缺少格式占位符
console.log('--- 测试3: 缺少格式占位符 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'数据库操作完成', '额外参数会被忽略');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式3异常捕获: %{public}s', e.message);
}
// 4. 格式字符串为空
console.log('--- 测试4: 格式字符串为空 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'', '参数1', '参数2');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式4异常捕获: %{public}s', e.message);
}
// 5. 复杂嵌套格式错误
console.log('--- 测试5: 复杂嵌套格式错误 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'系统资源使用 内存:%{public}d%% CPU:%{public}d%% 磁盘:%{public}d%%',
75, 'invalid_cpu', 90);
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式5异常捕获: %{public}s', e.message);
}
console.log('=== 异常格式日志测试完成 ===\n');
}
// 模拟边界条件日志生成
static generateBoundaryLogs() {
console.log('\n=== 开始测试边界条件日志 ===');
// 1. 超长字符串
const longString = 'A'.repeat(10000);
console.log('--- 测试1: 超长字符串 ---');
this.info(this.DOMAIN_APP, this.TAG_APP,
'超长日志内容长度:%{public}d 字符串预览:%{public}s',
longString.length, longString.substring(0, 100));
// 2. 极端数值
console.log('--- 测试2: 极端数值 ---');
this.info(this.DOMAIN_APP, this.TAG_APP,
'极端数值测试 负数:%{public}d 零:%{public}d 超大数:%{public}d',
-999999, 0, 999999999);
// 3. 特殊字符
console.log('--- 测试3: 特殊字符 ---');
const specialChars = '特殊字符测试: !@#$%^&*()_+-=[]{}|;:,.<>?中文测试';
this.info(this.DOMAIN_APP, this.TAG_APP,
'特殊字符日志:%{public}s', specialChars);
// 4. 空值和undefined
console.log('--- 测试4: 空值和undefined ---');
this.info(this.DOMAIN_APP, this.TAG_APP,
'空值测试 null:%{public}s undefined:%{public}s', null, undefined);
console.log('=== 边界条件日志测试完成 ===\n');
}
}
// 运行测试
console.log('开始测试异常格式日志功能...\n');
TestAbnormalLogGenerator.generateAbnormalFormatLogs();
TestAbnormalLogGenerator.generateBoundaryLogs();
console.log('所有测试完成!');
\ No newline at end of file
plugins {
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.androidLibrary) apply false
alias(libs.plugins.composeMultiplatform) apply false
alias(libs.plugins.composeCompiler) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
}
#!/bin/bash
# 清理HarmonyOS项目缓存脚本
echo "开始清理项目缓存..."
# 清理构建缓存
echo "清理build目录..."
rm -rf entry/build
rm -rf build
# 清理hvigor缓存
echo "清理hvigor缓存..."
rm -rf .hvigor
rm -rf hvigor/hvigor-cache
# 清理oh_modules
echo "清理oh_modules..."
rm -rf oh_modules
# 清理IDE相关缓存
echo "清理IDE缓存..."
find . -name "*.iml" -delete
find . -name ".idea" -type d -exec rm -rf {} + 2>/dev/null || true
echo "缓存清理完成!"
echo "建议操作:"
echo "1. 重启DevEco Studio"
echo "2. 重新导入项目"
echo "3. 重新构建项目"
\ No newline at end of file
/**
能导入的包
1. 来源插件
在 当前的 build.gradle.kts 定义可以搭配的插件
plugins {
alias(libs.plugins.androidApplication) // 提供 android.* 相关类
alias(libs.plugins.kotlinMultiplatform) // 提供 org.jetbrains.kotlin.gradle.* 相关类
alias(libs.plugins.composeMultiplatform) // 提供 compose 相关类
}
插件的版本在 libs.versions.toml 中定义:
2.Gradle 核心类
Gradle 本身提供的核心类(如 Copy、JavaVersion 等)自动可用,无需额外配置
*/
// 导入ExperimentalKotlinGradlePluginApi注解,用于开启Kotlin插件实验特性
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
// 导入JvmTarget,用于指定JVM的目标版本
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
// 应用Kotlin多平台插件
alias(libs.plugins.kotlinMultiplatform)
// 应用Compose多平台插件
alias(libs.plugins.composeMultiplatform)
// 应用Compose编译器插件
alias(libs.plugins.composeCompiler)
}
/**
Kotlin Multiplatform 配置
插件 libs.plugins.kotlinMultiplatform
负责 Kotlin 代码编译
Android: Kotlin/JVM → .class 文件 │
iOS: Kotlin/Native → LLVM IR │
OHOS: Kotlin/Native → LLVM IR
kotlin {
├── 目标平台 (androidTarget, jvm, iosX64, etc.)
│ ├── compilerOptions
│ └── binaries
├── cocoapods (iOS 特定)
├── sourceSets
│ ├── commonMain/commonTest
│ ├── platformMain/platformTest
│ └── customSourceSets
└── 其他配置
}
*/
kotlin {
// 配置OHOS(华为鸿蒙)arm64目标
ohosArm64 {
binaries.sharedLib {
baseName = "kn" // 共享库名称为kn
export(libs.compose.multiplatform.export) // 导出compose多平台库的接口
}
val main by compilations.getting // 获取主编译内容
val resource by main.cinterops.creating {
// 配置C interop(cinterop)资源
defFile(file("src/ohosArm64Main/cinterop/resource.def")) // cinterop定义文件
includeDirs(file("src/ohosArm64Main/cinterop/include")) // cinterop包含目录
}
}
// 配置各平台的依赖关系
sourceSets {
commonMain.dependencies {
implementation(compose.runtime) // 添加compose runtime依赖
implementation(compose.foundation) // 添加compose基础依赖
implementation(compose.material) // 添加compose material依赖
implementation(compose.ui) // 添加compose ui依赖
implementation(compose.components.resources) // 添加compose组件资源依赖
implementation(compose.components.uiToolingPreview) // 添加compose ui工具预览依赖
implementation(libs.kotlinx.coroutines.core) // 官方协程核心库
implementation(libs.atomicFu) // Kotlin AtomicFu原子库
}
val ohosArm64Main by getting {
dependencies {
api(libs.compose.multiplatform.export) // 导出compose多平台接口给依赖消费者
}
}
}
}
// 为 ohosArm64 目标配置依赖处理
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
val cmpVersion = versionCatalog.findVersion("composeMultiplatform")
.orElseThrow { IllegalStateException("Missing version composeMultiplatform in version catalog") }
.requiredVersion
val skikoOverrideByCmpVersion = mapOf(
"1.9.2-ez-001" to "0.9.22.2-ez-001",
// 仅在需要强制的 CMP 版本这里新增
)
val skikoOhosOverride = skikoOverrideByCmpVersion[cmpVersion]
configurations.all {
val configName = name
if (configName.contains("ohos", ignoreCase = true)) {
incoming.afterResolve {
val resolvedSkiko = resolutionResult.allComponents
.mapNotNull { it.moduleVersion }
.firstOrNull { it.group == "org.jetbrains.skiko" && it.name == "skiko" }
logger.lifecycle(
"Resolved skiko for $configName: " +
(resolvedSkiko?.let { "${it.group}:${it.name}:${it.version}" } ?: "not found")
)
}
// exclude(group = "org.jetbrains.androidx.lifecycle")
// exclude(group = "org.jetbrains.androidx.savedstate")
}
resolutionStrategy {
eachDependency {
// 如果是 skiko 依赖,检查配置名称是否包含 ohos
if (requested.group == "org.jetbrains.skiko" && requested.name == "skiko") {
if (configName.contains("ohos", ignoreCase = true)) {
skikoOhosOverride?.let { useVersion(it) }
}
}
// 强制指定 androidx.collection 版本,避免冲突
if (requested.group == "androidx.collection" && requested.name == "collection") {
useVersion(libs.versions.androidx.collection.get())
}
}
}
exclude(group = "androidx.collection", module = "collection-jvm")
}
// Harmony App 输出目录(支持命令行 --harmonyAppPath)
val harmonyAppDir: File = run {
val cliPath = project.findProperty("harmonyAppPath") as String?
if (cliPath.isNullOrBlank()) {
// 默认:项目根目录 /harmonyApp
rootProject.file("harmonyApp")
} else {
// 命令行传入的路径
file(cliPath)
}
}
// 字符串首字母大写工具函数
fun String.capitalizeUS(): String = this.replaceFirstChar {
if (it.isLowerCase()) it.titlecase() else it.toString()
}
// 为不同类型(debug、release)OHOS构建注册Copy任务并发布到Harmony App目录
arrayOf("debug", "release").forEach { type ->
tasks.register<Copy>("publish${type.capitalizeUS()}BinariesToHarmonyApp") {
group = "harmony" // 归类到harmony任务组
dependsOn("link${type.capitalizeUS()}SharedOhosArm64") // 依赖于OHOS shared lib的链接任务
into(harmonyAppDir) // 输出目标目录
from("build/bin/ohosArm64/${type}Shared/libkn_api.h") { // 复制头文件
into("entry/src/main/cpp/include/") // 指定目录
}
from(project.file("build/bin/ohosArm64/${type}Shared/libkn.so")) { // 复制共享库文件
into("/entry/libs/arm64-v8a/") // 指定目标目录
}
}
}
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="450dp"
android:height="450dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M56.25,18V46L32,60 7.75,46V18L32,4Z"
android:fillColor="#6075f2"/>
<path
android:pathData="m41.5,26.5v11L32,43V60L56.25,46V18Z"
android:fillColor="#6b57ff"/>
<path
android:pathData="m32,43 l-9.5,-5.5v-11L7.75,18V46L32,60Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="23.131"
android:centerY="18.441"
android:gradientRadius="42.132"
android:type="radial">
<item android:offset="0" android:color="#FF5383EC"/>
<item android:offset="0.867" android:color="#FF7F52FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M22.5,26.5 L32,21 41.5,26.5 56.25,18 32,4 7.75,18Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="44.172"
android:startY="4.377"
android:endX="17.973"
android:endY="34.035"
android:type="linear">
<item android:offset="0" android:color="#FF33C3FF"/>
<item android:offset="0.878" android:color="#FF5383EC"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m32,21 l9.526,5.5v11L32,43 22.474,37.5v-11z"
android:fillColor="#000000"/>
</vector>
package com.dong.test1
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@Composable
internal fun App() {
MaterialTheme {
// 使用 Page 类型的状态,修复类型推断报错
var page by remember { mutableStateOf<com.dong.test1.navigation.Page>(com.dong.test1.navigation.Page.Home) }
// 首页状态提升:滚动、搜索、分组展开状态
val listState = androidx.compose.foundation.lazy.rememberLazyListState()
var searchQuery by remember { mutableStateOf("") }
val expandedGroups = remember {
mutableStateMapOf<com.dong.test1.navigation.ComposeGroup, Boolean>().apply {
com.dong.test1.navigation.ComposeGroup.entries.forEach { put(it, true) }
}
}
Column(
modifier = Modifier
.safeContentPadding()
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
when (val p = page) {
is com.dong.test1.navigation.Page.Home -> {
HomeScreen(
onSelect = { demo ->
page = com.dong.test1.navigation.Page.Detail(demo)
},
listState = listState,
searchQuery = searchQuery,
onSearchChange = { searchQuery = it },
expandedGroups = expandedGroups
)
}
is com.dong.test1.navigation.Page.Detail -> {
DemoScreen(demo = p.demo, onBack = { page = com.dong.test1.navigation.Page.Home })
}
}
}
}
}
package com.dong.test1
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.dong.test1.navigation.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import com.dong.test1.demos.material.*
import com.dong.test1.demos.ui.UiBoxDemo
import com.dong.test1.demos.benchmark.*
import com.dong.test1.demos.foundation.FoundationBasicTextDemo
import com.dong.test1.demos.foundation.FoundationLazyColumnDemo
import com.dong.test1.demos.ui.TestLogDemo
@Composable
internal fun HomeScreen(
onSelect: (com.dong.test1.navigation.ComponentDemo) -> Unit,
listState: androidx.compose.foundation.lazy.LazyListState,
searchQuery: String,
onSearchChange: (String) -> Unit,
expandedGroups: MutableMap<com.dong.test1.navigation.ComposeGroup, Boolean>
) {
val grouped = com.dong.test1.navigation.demosByGroup()
val filtered = grouped.mapValues { (_, demos) ->
if (searchQuery.isBlank()) demos
else demos.filter { d ->
d.title.contains(searchQuery, ignoreCase = true) ||
d.id.contains(searchQuery, ignoreCase = true)
}
}.filterValues { it.isNotEmpty() || searchQuery.isBlank() }
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 8.dp)
) {
// 顶部固定搜索框(避免 iOS LazyColumn 首项兼容性问题)
Card(backgroundColor = MaterialTheme.colors.surface) {
OutlinedTextField(
value = searchQuery,
onValueChange = onSearchChange,
label = { Text("搜索") },
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
singleLine = true
)
}
Spacer(Modifier.height(12.dp))
androidx.compose.foundation.lazy.LazyColumn(
modifier = Modifier.fillMaxSize(),
state = listState,
contentPadding = PaddingValues(vertical = 12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
com.dong.test1.navigation.ComposeGroup.entries.forEach { group ->
val demos = filtered[group] ?: emptyList()
if (demos.isEmpty() && searchQuery.isNotBlank()) {
// 搜索无结果时该组隐藏
} else {
val expanded = expandedGroups[group] != false
item {
Card(
backgroundColor = Color.LightGray.copy(alpha = 0.3f), // surfaceVariant replacement
modifier = Modifier
.fillMaxWidth()
.clickable { expandedGroups[group] = !expanded }
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(
com.dong.test1.navigation.groupTitles[group] ?: group.name,
style = MaterialTheme.typography.h6
)
val countText =
if (searchQuery.isNotBlank()) "匹配:${demos.size}" else "共 ${demos.size} 项"
Text(countText, style = MaterialTheme.typography.caption)
}
Text(
text = if (expanded) "收起 ▾" else "展开 ▸",
color = MaterialTheme.colors.primary
)
}
}
}
if (expanded) {
items(demos) { demo ->
Card(backgroundColor = MaterialTheme.colors.surface) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onSelect(demo) }
.padding(16.dp), // Increased padding for better touch target
verticalAlignment = Alignment.CenterVertically
) {
Text(demo.title, style = MaterialTheme.typography.body1)
}
}
Divider()
}
}
}
}
}
}
}
@Composable
internal fun DemoScreen(demo: ComponentDemo, onBack: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(text = demo.title, style = MaterialTheme.typography.h5)
OutlinedButton(onClick = onBack) { Text("返回") }
}
Divider()
when (demo.id) {
// ui
"log"-> TestLogDemo()
"ui_box" -> UiBoxDemo()
// foundation
"foundation_basic_text" -> FoundationBasicTextDemo()
"foundation_lazy_column" -> FoundationLazyColumnDemo()
// benchmark
"benchmark_1500_text" -> Compose1500Text()
"benchmark_1500_view" -> ComposeView1500Page()
// material
"material_alert_dialog" -> AlertDialogSamples()
"material_app_bar" -> AppBarSamples()
"material_backdrop_scaffold" -> BackdropScaffoldSamples()
"material_badge" -> BadgeSamples()
"material_bottom_navigation" -> BottomNavigationSamples()
"material_bottom_sheet_scaffold" -> BottomSheetScaffoldSamples()
"material_button_samples" -> ButtonSamples()
"material_card_samples" -> CardSamples()
"material_content_alpha" -> ContentAlphaSamples()
"material_drawer_samples" -> DrawerSamples()
"material_elevation_samples" -> ElevationSamples()
"material_exposed_dropdown_menu" -> ExposedDropdownMenuSamples()
"material_fab_samples" -> FloatingActionButtonSamples()
"material_icon_button_samples" -> IconButtonSamples()
"material_list_samples" -> ListSamples()
"material_menu_samples" -> MenuSamples()
"material_modal_bottom_sheet" -> ModalBottomSheetSamples()
"material_navigation_rail" -> NavigationRailSample()
"material_progress_indicator" -> ProgressIndicatorSamples()
"material_pull_refresh" -> PullRefreshSamples()
"material_selection_controls" -> SelectionControlsSamples()
"material_slider_sample" -> SliderSample()
"material_surface_samples" -> SurfaceSamples()
"material_swipeable_samples" -> SwipeableSamples()
"material_swipe_to_dismiss" -> SwipeToDismissSamples()
"material_tab_samples" -> TabSamples()
"material_text_field_samples" -> TextFieldSamples()
"material_text_samples" -> TextSamples()
"material_theme_samples" -> ThemeSamples()
else -> {
if (demo.group == com.dong.test1.navigation.ComposeGroup.Platform) {
com.dong.test1.PlatformDemo(demo.id)
}
}
}
}
}
package com.dong.test1
class Greeting {
private val platform = getPlatform()
fun greet(): String {
return "Hello, ${platform.name}!"
}
}
\ No newline at end of file
package com.dong.test1
interface LogController {
fun stop()
val isRunning: Boolean
}
\ No newline at end of file
package com.dong.test1
interface Platform {
val name: String
}
expect fun getPlatform(): Platform
internal data class PlatformDemoItem(val id: String, val title: String)
internal expect fun getPlatformDemoList(): List<PlatformDemoItem>
@androidx.compose.runtime.Composable
internal expect fun PlatformDemo(id: String)
package com.dong.test1
//speed日志生成速度
expect fun startLog(speed: Int, onLogGenerated: ((Int) -> Unit)? = null, onTimerUpdated: ((Long) -> Unit)? = null): LogController
// 创建独立的计时器控制器
expect fun createTimer(): TimerController
\ No newline at end of file
package com.dong.test1
interface TimerController {
fun start()
fun stop()
fun reset()
val isRunning: Boolean
val elapsedTime: Long
}
\ No newline at end of file
package com.dong.test1.demos.benchmark
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
internal fun Compose1500Text() {
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
repeat(1500) { index ->
Text(
text = "Compose1500Text Item #$index",
fontSize = 16.sp,
modifier = Modifier
.width(300.dp)
.height(50.dp)
.border(1.dp, Color.Gray)
.padding(10.dp)
)
}
}
}
package com.dong.test1.demos.benchmark
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.ExperimentalResourceApi
@OptIn(ExperimentalResourceApi::class)
@Composable
internal fun ComposeView1500Page() {
val loaded = remember { mutableStateOf(false) }
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
repeat(1500) { index ->
Box(
modifier = Modifier
.size(300.dp, 100.dp)
.border(
width = 2.dp,
color = Color.Red,
)
.then(
if (index == 1499) Modifier.onGloballyPositioned {
loaded.value = true
//trace_tag_end()
} else Modifier
)
) {
Text(
text = "Item #$index",
)
}
}
}
if (loaded.value) {
println("页面加载完成 ✅")
}
}
\ No newline at end of file
package com.dong.test1.demos.foundation
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicText
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
internal fun FoundationBasicTextDemo() {
var text by remember { mutableStateOf("Hello Compose") }
var size by remember { mutableStateOf(18f) }
var colorToggle by remember { mutableStateOf(false) }
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(value = text, onValueChange = { text = it }, label = { Text("内容") })
Text("字体大小: ${size.toInt()}sp")
Slider(value = size, onValueChange = { size = it }, valueRange = 12f..48f)
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(checked = colorToggle, onCheckedChange = { colorToggle = it })
Text("使用高亮颜色")
}
Box(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colors.surface)
.padding(12.dp)
) {
BasicText(
text = text,
style = androidx.compose.ui.text.TextStyle(
fontSize = size.sp,
color = if (colorToggle) MaterialTheme.colors.primary else Color.Unspecified
)
)
}
}
}
package com.dong.test1.demos.foundation
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Slider
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
internal fun FoundationLazyColumnDemo() {
var count by remember { mutableStateOf(10) }
var spaced by remember { mutableStateOf(4) }
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text("条目数量: $count")
Slider(value = count.toFloat(), onValueChange = { count = it.toInt() }, valueRange = 1f..50f)
Text("条目间距: ${spaced}dp")
Slider(value = spaced.toFloat(), onValueChange = { spaced = it.toInt() }, valueRange = 0f..24f)
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(220.dp)
.background(MaterialTheme.colors.surface),
contentPadding = PaddingValues(8.dp),
verticalArrangement = Arrangement.spacedBy(spaced.dp)
) {
items((1..count).toList()) { idx ->
Box(
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
.background(MaterialTheme.colors.secondary),
contentAlignment = Alignment.Center
) {
Text("Item #$idx")
}
}
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.AlertDialog
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.*
@Composable
internal fun AlertDialogSamples() {
var open by remember { mutableStateOf(true) }
var dismissOnClickOutside by remember { mutableStateOf(true) }
var dismissOnBackPress by remember { mutableStateOf(true) }
if (open) {
AlertDialog(
onDismissRequest = {
if (dismissOnBackPress) open = false
},
title = { Text("AlertDialog") },
text = { Text("展示标题、内容、确认/取消按钮,以及关闭行为。") },
confirmButton = {
TextButton(onClick = { open = false }) { Text("确认") }
},
dismissButton = {
TextButton(onClick = { if (dismissOnClickOutside) open = false }) { Text("取消") }
}
)
}
}
package com.dong.test1.demos.material
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
internal fun AppBarSamples() {
var title by remember { mutableStateOf("TopAppBar 标题") }
var showActions by remember { mutableStateOf(true) }
var elevation by remember { mutableStateOf(4f) }
Column {
TopAppBar(
title = { Text(title) },
actions = {
if (showActions) {
TextButton(onClick = { title = "点击了 Action" }) { Text("Action") }
}
},
elevation = elevation.dp
)
Spacer(Modifier.height(8.dp))
BottomAppBar {
Text("BottomAppBar")
}
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(value = title, onValueChange = { title = it }, label = { Text("标题") })
Text("阴影: ${elevation.toInt()}dp")
Slider(value = elevation, onValueChange = { elevation = it }, valueRange = 0f..16f)
Row {
Checkbox(checked = showActions, onCheckedChange = { showActions = it })
Text("显示 Action")
}
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class)
@Composable
internal fun BackdropScaffoldSamples() {
val scaffoldState = rememberBackdropScaffoldState(BackdropValue.Concealed)
val scope = rememberCoroutineScope()
var clicks by remember { mutableStateOf(0) }
BackdropScaffold(
scaffoldState = scaffoldState,
appBar = { TopAppBar(title = { Text("BackdropScaffold") }) },
backLayerContent = {
Column(Modifier.fillMaxWidth().padding(12.dp)) {
Text("后层内容")
Button(onClick = { clicks++ }) { Text("点击: $clicks") }
}
},
frontLayerContent = {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Button(
onClick = {
scope.launch {
if (scaffoldState.isConcealed) scaffoldState.reveal() else scaffoldState.conceal()
}
}
) { Text(if (scaffoldState.isConcealed) "展开前层" else "收起前层") }
}
}
)
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
@Composable
internal fun BadgeSamples() {
var count by remember { mutableStateOf(3) }
BadgedBox(badge = { Text("$count") }) {
Text("带徽章的内容")
}
Row(Modifier.padding(12.dp), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = { count++ }) { Text("+1") }
Button(onClick = { count = 0 }) { Text("清零") }
}
}
package com.dong.test1.demos.material
import androidx.compose.material.*
import androidx.compose.runtime.*
@Composable
internal fun BottomNavigationSamples() {
var selected by remember { mutableStateOf(0) }
BottomNavigation {
listOf("主页", "消息", "设置").forEachIndexed { index, label ->
BottomNavigationItem(
selected = selected == index,
onClick = { selected = index },
icon = { },
label = { Text(label) }
)
}
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class)
@Composable
internal fun BottomSheetScaffoldSamples() {
val sheetState = rememberBottomSheetScaffoldState()
val scope = rememberCoroutineScope()
BottomSheetScaffold(
scaffoldState = sheetState,
sheetContent = {
Column(Modifier.padding(12.dp)) {
Text("BottomSheet 内容")
Text("可在此添加交互与属性")
}
},
sheetPeekHeight = 64.dp
) { padding ->
Column(Modifier.padding(padding).padding(12.dp)) {
Button(onClick = {
scope.launch {
val state = sheetState.bottomSheetState
if (state.isCollapsed) state.expand() else state.collapse()
}
}) { Text("展开/收起 BottomSheet") }
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
@Composable
internal fun ButtonSamples() {
var enabled by remember { mutableStateOf(true) }
var clicks by remember { mutableStateOf(0) }
Button(
enabled = enabled,
onClick = { clicks++ },
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFF4CAF50), contentColor = Color.White)
) {
Text("Material Button 点击: $clicks")
}
}
package com.dong.test1.demos.material
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
@Composable
internal fun CardSamples() {
var elevation by remember { mutableStateOf(4f) }
Card(elevation = elevation.dp) {
Column(Modifier.padding(12.dp)) {
Text("Material Card 标题")
Text("阴影 elevation: ${elevation.toInt()}dp")
}
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
@Composable
internal fun ContentAlphaSamples() {
var disabled by remember { mutableStateOf(false) }
Column(Modifier.padding(12.dp)) {
Row {
Checkbox(checked = disabled, onCheckedChange = { disabled = it })
Text("使用 ContentAlpha.disabled")
}
CompositionLocalProvider(LocalContentAlpha provides if (disabled) ContentAlpha.disabled else ContentAlpha.high) {
Text("受 ContentAlpha 控制的文本")
}
Text("不受影响的文本")
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
@Composable
internal fun DrawerSamples() {
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalDrawer(
drawerState = drawerState,
drawerContent = {
Column(Modifier.padding(12.dp)) {
Text("Drawer 内容")
Button(onClick = { scope.launch { drawerState.close() } }) { Text("关闭") }
}
}
) {
Column(Modifier.padding(12.dp)) {
Button(onClick = { scope.launch { drawerState.open() } }) { Text("打开 Drawer") }
}
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.Slider
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
@Composable
internal fun ElevationSamples() {
var elevation by remember { mutableStateOf(4f) }
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text("阴影: ${elevation.toInt()}dp")
Slider(value = elevation, onValueChange = { elevation = it }, valueRange = 0f..24f)
Surface(elevation = elevation.dp) {
Box(Modifier.size(120.dp).padding(12.dp)) { Text("Surface with elevation") }
}
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterialApi::class)
@Composable
internal fun ExposedDropdownMenuSamples() {
val options = listOf("选项 A", "选项 B", "选项 C")
var expanded by remember { mutableStateOf(false) }
var selected by remember { mutableStateOf(options.first()) }
ExposedDropdownMenuBox(expanded = expanded, onExpandedChange = { expanded = !expanded }) {
OutlinedTextField(
value = selected, onValueChange = {}, readOnly = true, label = { Text("选择项") }
)
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
options.forEach { option ->
DropdownMenuItem(onClick = { selected = option; expanded = false }) {
Text(option)
}
}
}
}
Spacer(Modifier.height(8.dp))
Text("当前选择: $selected")
}
package com.dong.test1.demos.material
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Text
import androidx.compose.runtime.*
@Composable
internal fun FloatingActionButtonSamples() {
var clicks by remember { mutableStateOf(0) }
FloatingActionButton(onClick = { clicks++ }) { Text("$clicks") }
}
package com.dong.test1.demos.material
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.runtime.*
@Composable
internal fun IconButtonSamples() {
var clicks by remember { mutableStateOf(0) }
IconButton(onClick = { clicks++ }) {
Text("★")
}
Text("点击次数: $clicks")
}
@file:OptIn(androidx.compose.material.ExperimentalMaterialApi::class)
package com.dong.test1.demos.material
import androidx.compose.material.ListItem
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
@Composable
internal fun ListSamples() {
val items = (1..20).map { "Item $it" }
LazyColumn(contentPadding = PaddingValues(8.dp), verticalArrangement = Arrangement.spacedBy(4.dp)) {
items(items) { label ->
ListItem(text = { Text(label) }, secondaryText = { Text("副标题") })
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
@Composable
internal fun MenuSamples() {
var expanded by remember { mutableStateOf(false) }
Column {
Button(onClick = { expanded = true }) { Text("打开菜单") }
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DropdownMenuItem(onClick = { expanded = false }) { Text("菜单项 1") }
DropdownMenuItem(onClick = { expanded = false }) { Text("菜单项 2") }
}
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class)
@Composable
internal fun ModalBottomSheetSamples() {
val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
ModalBottomSheetLayout(
sheetState = sheetState,
sheetContent = { Column(Modifier.padding(12.dp)) { Text("ModalBottomSheet 内容") } }
) {
Column(Modifier.padding(12.dp)) {
Button(onClick = { scope.launch { sheetState.show() } }) { Text("显示") }
Spacer(Modifier.height(8.dp))
Button(onClick = { scope.launch { sheetState.hide() } }) { Text("隐藏") }
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.NavigationRail
import androidx.compose.material.NavigationRailItem
import androidx.compose.material.Text
import androidx.compose.runtime.*
@Composable
internal fun NavigationRailSample() {
var selected by remember { mutableStateOf(0) }
NavigationRail {
listOf("主页", "消息", "设置").forEachIndexed { index, label ->
NavigationRailItem(
selected = selected == index,
onClick = { selected = index },
icon = { Text("★") },
label = { Text(label) }
)
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
internal fun ProgressIndicatorSamples() {
var progress by remember { mutableStateOf(0.3f) }
Column(Modifier.fillMaxWidth().padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
LinearProgressIndicator(progress = progress, modifier = Modifier.fillMaxWidth())
CircularProgressIndicator(progress = progress)
}
}
package com.dong.test1.demos.material
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Composable
internal fun PullRefreshSamples() {
var refreshing by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = {
scope.launch {
refreshing = true
delay(1000)
refreshing = false
}
}) { Text("手动触发刷新") }
if (refreshing) LinearProgressIndicator(Modifier.fillMaxWidth())
Text(if (refreshing) "刷新中..." else "刷新完成")
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
@Composable
internal fun SelectionControlsSamples() {
var checked by remember { mutableStateOf(true) }
var selected by remember { mutableStateOf(0) }
var switchOn by remember { mutableStateOf(true) }
Column(Modifier.padding(12.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(checked = checked, onCheckedChange = { checked = it })
Text("Checkbox: ${if (checked) "选中" else "未选"}")
}
Row(verticalAlignment = androidx.compose.ui.Alignment.CenterVertically) {
RadioButton(selected = selected == 0, onClick = { selected = 0 })
RadioButton(selected = selected == 1, onClick = { selected = 1 })
Text("Radio 选择: $selected")
}
Row(verticalAlignment = androidx.compose.ui.Alignment.CenterVertically) {
Switch(checked = switchOn, onCheckedChange = { switchOn = it })
Text("Switch: ${if (switchOn) "" else ""}")
}
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.layout.*
@Composable
internal fun SliderSample() {
var value by remember { mutableStateOf(0.5f) }
Column(Modifier.padding(12.dp)) {
Text("当前值: ${kotlin.math.round(value * 10.0f) / 10.0f}")
Slider(value = value, onValueChange = { value = it }, valueRange = 0f..1f, steps = 4)
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
internal fun SurfaceSamples() {
var elevation by remember { mutableStateOf(6f) }
var rounded by remember { mutableStateOf(12f) }
var bg by remember { mutableStateOf(Color(0xFFE0F7FA)) }
Column(Modifier.padding(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Surface(shape = RoundedCornerShape(rounded.dp), elevation = elevation.dp, color = bg) {
Column(Modifier.padding(12.dp)) {
Text("Surface 属性演示")
Text("elevation=${elevation.toInt()} shape=${rounded.toInt()} color=${bg}")
}
}
Text("elevation: ${elevation.toInt()}dp"); Slider(value = elevation, onValueChange = { elevation = it }, valueRange = 0f..24f)
Text("圆角: ${rounded.toInt()}dp"); Slider(value = rounded, onValueChange = { rounded = it }, valueRange = 0f..32f)
}
}
package com.dong.test1.demos.material
import androidx.compose.ui.Modifier
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterialApi::class)
@Composable
internal fun SwipeToDismissSamples() {
val dismissState = rememberDismissState()
SwipeToDismiss(
state = dismissState,
background = {
Box(Modifier.fillMaxWidth().height(64.dp)) { Text("滑动删除背景") }
},
dismissContent = {
Box(Modifier.fillMaxWidth().height(64.dp)) { Text("可滑动删除内容") }
}
)
Text("当前状态: ${dismissState.currentValue}")
}
@file:OptIn(androidx.compose.material.ExperimentalMaterialApi::class)
package com.dong.test1.demos.material
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.DismissDirection
import androidx.compose.material.DismissValue
import androidx.compose.material.Divider
import androidx.compose.material.ListItem
import androidx.compose.material.SwipeToDismiss
import androidx.compose.material.Text
import androidx.compose.material.rememberDismissState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@Composable
internal fun SwipeableSamples() {
val mails = remember { mutableStateListOf("Mail 1", "Mail 2", "Mail 3") }
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = 8.dp)
) {
items(mails, key = { mail -> mail }) { mail ->
val dismissState = rememberDismissState(
confirmStateChange = { newValue: DismissValue ->
if (newValue == DismissValue.DismissedToEnd || newValue == DismissValue.DismissedToStart) {
mails.remove(mail)
}
true
}
)
SwipeToDismiss(
state = dismissState,
directions = setOf(
DismissDirection.StartToEnd,
DismissDirection.EndToStart
),
background = {
val bgColor = when (dismissState.targetValue) {
DismissValue.Default -> Color.Transparent
DismissValue.DismissedToEnd -> Color(0xFF2E7D32) // Archive
DismissValue.DismissedToStart -> Color(0xFFC62828) // Delete
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(64.dp)
.background(bgColor),
contentAlignment = Alignment.CenterStart
) {
Text(
text = if (dismissState.targetValue == DismissValue.DismissedToEnd) "Archive" else "Delete",
color = Color.White,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(start = 16.dp)
)
}
},
dismissContent = {
ListItem(
text = { Text(mail) },
secondaryText = { Text("Swipe me left or right") }
)
}
)
Divider()
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.Tab
import androidx.compose.material.TabRow
import androidx.compose.material.Text
import androidx.compose.runtime.*
@Composable
internal fun TabSamples() {
var selectedTab by remember { mutableStateOf(0) }
val tabs = listOf("Tab1", "Tab2", "Tab3")
TabRow(selectedTabIndex = selectedTab) {
tabs.forEachIndexed { index, title ->
Tab(selected = selectedTab == index, onClick = { selectedTab = index }, text = { Text(title) })
}
}
}
package com.dong.test1.demos.material
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.runtime.*
@Composable
internal fun TextFieldSamples() {
var text by remember { mutableStateOf("") }
var enabled by remember { mutableStateOf(true) }
var isError by remember { mutableStateOf(false) }
OutlinedTextField(
value = text,
onValueChange = { text = it },
enabled = enabled,
isError = isError,
label = { Text("Label") },
placeholder = { Text("Placeholder") }
)
}
package com.dong.test1.demos.material
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
internal fun TextSamples() {
var size by remember { mutableStateOf(16f) }
var bold by remember { mutableStateOf(false) }
Column(Modifier.padding(12.dp)) {
Text("普通文本", fontSize = size.sp, fontWeight = if (bold) FontWeight.Bold else FontWeight.Normal)
Text("副标题", style = MaterialTheme.typography.subtitle1)
Text("标题", style = MaterialTheme.typography.h6)
Text("正文", style = MaterialTheme.typography.body1)
Text("按钮", style = MaterialTheme.typography.button)
Text("说明文字", style = MaterialTheme.typography.caption)
Spacer(Modifier.height(8.dp))
Text("字体大小: ${size.toInt()}sp"); Slider(value = size, onValueChange = { size = it }, valueRange = 12f..36f)
Row { Checkbox(checked = bold, onCheckedChange = { bold = it }); Text("加粗") }
}
}
package com.dong.test1.demos.material
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
@Composable
internal fun ThemeSamples() {
// 演示 MaterialTheme 的基本用法;完整主题切换后续扩展
Text("当前 MaterialTheme.typography.body1 示例文本")
}
package com.dong.test1.demos.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalLayoutApi::class)
@Composable
internal fun UiBoxDemo() {
val alignments = listOf(
Alignment.TopStart, Alignment.TopCenter, Alignment.TopEnd,
Alignment.CenterStart, Alignment.Center, Alignment.CenterEnd,
Alignment.BottomStart, Alignment.BottomCenter, Alignment.BottomEnd
)
var selected by remember { mutableStateOf(Alignment.Center) }
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text("Alignment")
FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
alignments.forEach { a ->
val label = a.toString().removePrefix("Alignment.")
if (selected == a) {
Button(onClick = { selected = a }) {
Text(label)
}
} else {
OutlinedButton(onClick = { selected = a }) {
Text(label)
}
}
}
}
Box(
modifier = Modifier
.size(220.dp)
.background(MaterialTheme.colors.surface) // surfaceVariant -> surface
) {
Box(
modifier = Modifier
.size(48.dp)
.align(selected)
.background(MaterialTheme.colors.primary) // primary -> primary
)
}
}
}
package com.dong.test1.demos.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import com.dong.test1.startLog
import com.dong.test1.createTimer
import com.dong.test1.LogController
import com.dong.test1.TimerController
import kotlinx.coroutines.delay
@OptIn(ExperimentalLayoutApi::class)
@Composable
internal fun TestLogDemo() {
// 日志参数状态
var logSpeed by remember { mutableStateOf("100") }
var logCount by remember { mutableStateOf(0) }
var isGenerating by remember { mutableStateOf(false) }
var logController by remember { mutableStateOf<LogController?>(null) }
// 计时器状态
var timerController by remember { mutableStateOf<TimerController?>(null) }
var displayTime by remember { mutableStateOf(0L) }
// 初始化计时器
LaunchedEffect(Unit) {
timerController = createTimer()
}
// 定期更新显示时间
LaunchedEffect(timerController) {
while (true) {
delay(100) // 每100ms更新一次显示
displayTime = timerController?.elapsedTime ?: 0
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
// 计时器显示区域
Card(backgroundColor = MaterialTheme.colors.surface) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
"运行时间",
style = MaterialTheme.typography.h6,
modifier = Modifier.padding(bottom = 12.dp)
)
// 时间显示
Card(
backgroundColor = MaterialTheme.colors.primary.copy(alpha = 0.1f),
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
"${displayTime}秒",
style = MaterialTheme.typography.h4,
color = MaterialTheme.colors.primary
)
if (isGenerating) {
Text(
"日志生成中...",
style = MaterialTheme.typography.caption,
color = MaterialTheme.colors.secondary
)
}
}
}
}
}
// 日志生成功能区域
Card(backgroundColor = MaterialTheme.colors.surface) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
"日志生成工具",
style = MaterialTheme.typography.h6,
modifier = Modifier.padding(bottom = 12.dp)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
OutlinedTextField(
value = logSpeed,
onValueChange = { newValue ->
// 只允许数字输入
if (newValue.all { it.isDigit() }) {
logSpeed = newValue
}
},
label = { Text("间隔(ms)") },
modifier = Modifier.weight(1f),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
singleLine = true
)
}
Spacer(Modifier.height(12.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Button(
onClick = {
val speed = logSpeed.toIntOrNull() ?: 100
logCount = 0
// 重置并启动计时器
timerController?.reset()
timerController?.start()
// 启动日志生成
isGenerating = true
logController = startLog(speed,
onLogGenerated = { count ->
logCount = count
},
onTimerUpdated = { time ->
// 日志生成的计时现在只用于内部统计,不更新UI
}
)
},
modifier = Modifier.weight(1f),
enabled = logSpeed.isNotEmpty() && !isGenerating
) {
Text("开始生成")
}
Button(
onClick = {
logController?.stop()
timerController?.stop()
isGenerating = false
},
modifier = Modifier.weight(1f),
enabled = isGenerating
) {
Text("停止生成")
}
}
// 显示日志生成状态
if (isGenerating || logCount > 0) {
Spacer(Modifier.height(12.dp))
Card(
backgroundColor = MaterialTheme.colors.secondary.copy(alpha = 0.1f),
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
"生成日志数量",
style = MaterialTheme.typography.subtitle1,
color = MaterialTheme.colors.secondary
)
Text(
"$logCount 条",
style = MaterialTheme.typography.h4,
color = MaterialTheme.colors.secondary,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
}
}
}
}
\ No newline at end of file
package com.dong.test1.navigation
enum class ComposeGroup {
Ui, Foundation, Material, Benchmark, Platform
}
data class ComponentDemo(
val id: String,
val title: String,
val group: ComposeGroup
)
val componentDemos: List<ComponentDemo> = listOf(
// ui
ComponentDemo("ui_box", "Box", ComposeGroup.Ui),
ComponentDemo("log", "测试大量日志", ComposeGroup.Ui),
// foundation
ComponentDemo("foundation_basic_text", "BasicText", ComposeGroup.Foundation),
ComponentDemo("foundation_lazy_column", "LazyColumn", ComposeGroup.Foundation),
// material 组:新增完整清单
ComponentDemo("material_alert_dialog", "AlertDialogSample", ComposeGroup.Material),
ComponentDemo("material_app_bar", "AppBarSamples", ComposeGroup.Material),
ComponentDemo("material_backdrop_scaffold", "BackdropScaffoldSamples", ComposeGroup.Material),
ComponentDemo("material_badge", "BadgeSamples", ComposeGroup.Material),
ComponentDemo("material_bottom_navigation", "BottomNavigationSamples", ComposeGroup.Material),
ComponentDemo("material_bottom_sheet_scaffold", "BottomSheetScaffoldSamples", ComposeGroup.Material),
ComponentDemo("material_button_samples", "ButtonSamples", ComposeGroup.Material),
ComponentDemo("material_card_samples", "CardSamples", ComposeGroup.Material),
ComponentDemo("material_chip_samples", "ChipSamples", ComposeGroup.Material),
ComponentDemo("material_content_alpha", "ContentAlphaSamples", ComposeGroup.Material),
ComponentDemo("material_drawer_samples", "DrawerSamples", ComposeGroup.Material),
ComponentDemo("material_elevation_samples", "ElevationSamples", ComposeGroup.Material),
ComponentDemo("material_exposed_dropdown_menu", "ExposedDropdownMenuSamples", ComposeGroup.Material),
ComponentDemo("material_fab_samples", "FloatingActionButtonSamples", ComposeGroup.Material),
ComponentDemo("material_icon_button_samples", "IconButtonSamples", ComposeGroup.Material),
ComponentDemo("material_list_samples", "ListSamples", ComposeGroup.Material),
ComponentDemo("material_menu_samples", "MenuSamples", ComposeGroup.Material),
ComponentDemo("material_modal_bottom_sheet", "ModalBottomSheetSamples", ComposeGroup.Material),
ComponentDemo("material_navigation_rail", "NavigationRailSample", ComposeGroup.Material),
ComponentDemo("material_progress_indicator", "ProgressIndicatorSamples", ComposeGroup.Material),
ComponentDemo("material_pull_refresh", "PullRefreshSamples", ComposeGroup.Material),
ComponentDemo("material_scaffold_samples", "ScaffoldSamples", ComposeGroup.Material),
ComponentDemo("material_selection_controls", "SelectionControlsSamples", ComposeGroup.Material),
ComponentDemo("material_slider_sample", "SliderSample", ComposeGroup.Material),
ComponentDemo("material_surface_samples", "SurfaceSamples", ComposeGroup.Material),
ComponentDemo("material_swipeable_samples", "SwipeableSamples", ComposeGroup.Material),
ComponentDemo("material_swipe_to_dismiss", "SwipeToDismissSamples", ComposeGroup.Material),
ComponentDemo("material_tab_samples", "TabSamples", ComposeGroup.Material),
ComponentDemo("material_text_field_samples", "TextFieldSamples", ComposeGroup.Material),
ComponentDemo("material_text_samples", "TextSamples", ComposeGroup.Material),
ComponentDemo("material_theme_samples", "ThemeSamples", ComposeGroup.Material),
// benchmark
ComponentDemo("benchmark_1500_text", "1500 Text", ComposeGroup.Benchmark),
ComponentDemo("benchmark_1500_view", "1500 View", ComposeGroup.Benchmark),
)
val groupTitles: Map<ComposeGroup, String> = mapOf(
ComposeGroup.Ui to "compose.ui",
ComposeGroup.Foundation to "compose.foundation",
ComposeGroup.Material to "compose.material",
ComposeGroup.Platform to "Platform",
)
fun demosByGroup(): Map<ComposeGroup, List<ComponentDemo>> {
val standardDemos = ComposeGroup.entries.filter { it != ComposeGroup.Platform }
.associateWith { g -> componentDemos.filter { it.group == g } }
.toMutableMap()
val platformDemos = com.dong.test1.getPlatformDemoList().map {
ComponentDemo(
id = it.id,
title = it.title,
group = ComposeGroup.Platform
)
}
if (platformDemos.isNotEmpty()) {
standardDemos[ComposeGroup.Platform] = platformDemos
}
return standardDemos
}
fun demosJson(): String = buildString {
append('[')
componentDemos.forEachIndexed { index, demo ->
if (index > 0) append(',')
append("{\"id\":\"")
append(jsonEscape(demo.id))
append("\",\"title\":\"")
append(jsonEscape(demo.title))
append("\",\"group\":\"")
append(demo.group.name)
append("\"}")
}
append(']')
}
fun groupTitlesJson(): String = buildString {
append('{')
ComposeGroup.entries.forEachIndexed { index, group ->
if (index > 0) append(',')
append('"')
append(group.name)
append("\":\"")
append(jsonEscape(groupTitles[group] ?: group.name))
append('"')
}
append('}')
}
private fun jsonEscape(input: String): String = buildString(input.length) {
input.forEach { ch ->
when (ch) {
'\\' -> append("\\\\")
'"' -> append("\\\"")
'\n' -> append("\\n")
'\r' -> append("\\r")
'\t' -> append("\\t")
else -> append(ch)
}
}
}
sealed interface Page {
data object Home : Page
data class Detail(val demo: ComponentDemo) : Page
}
package com.dong.test1
import kotlin.test.Test
import kotlin.test.assertEquals
class ComposeAppCommonTest {
@Test
fun example() {
assertEquals(3, 1 + 2)
}
}
\ No newline at end of file
#ifndef GLOBAL_RAW_FILE_H
#define GLOBAL_RAW_FILE_H
#ifdef __cplusplus
extern "C" {
#endif
struct RawFile;
typedef struct RawFile RawFile;
int OH_ResourceManager_ReadRawFile(const RawFile *rawFile, void *buf, size_t length);
long OH_ResourceManager_GetRawFileSize(RawFile *rawFile);
void OH_ResourceManager_CloseRawFile(RawFile *rawFile);
#ifdef __cplusplus
};
#endif
/** @} */
#endif // GLOBAL_RAW_FILE_H
#ifndef GLOBAL_NATIVE_RESOURCE_MANAGER_H
#define GLOBAL_NATIVE_RESOURCE_MANAGER_H
#include "napi/native_api.h"
#include "raw_file.h"
#ifdef __cplusplus
extern "C" {
#endif
struct NativeResourceManager;
typedef struct NativeResourceManager NativeResourceManager;
NativeResourceManager *OH_ResourceManager_InitNativeResourceManager(napi_env env, napi_value jsResMgr);
void OH_ResourceManager_ReleaseNativeResourceManager(NativeResourceManager *resMgr);
RawFile *OH_ResourceManager_OpenRawFile(const NativeResourceManager *mgr, const char *fileName);
#ifdef __cplusplus
};
#endif
/** @} */
#endif // GLOBAL_NATIVE_RESOURCE_MANAGER_H
package = platform.resource
headers = raw_file_manager.h raw_file.h
package com.dong.test1
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.arkui.ArkUIView
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.interop.AdaptiveParams
import androidx.compose.ui.interop.InteropContainer
import androidx.compose.ui.napi.JsObject
import androidx.compose.ui.napi.js
private val NoOp: Any.() -> Unit = {}
@Composable
internal fun ArkUIView(
name: String,
modifier: Modifier,
parameter: JsObject = js(),
update: (JsObject) -> Unit = NoOp,
background: Color = Color.Unspecified,
updater: (ArkUIView) -> Unit = NoOp,
onCreate: (ArkUIView) -> Unit = NoOp,
onRelease: (ArkUIView) -> Unit = NoOp,
interactive: Boolean = true,
adaptiveParams: AdaptiveParams? = null,
tag: String? = null,
container: InteropContainer = InteropContainer.BACK
) = androidx.compose.ui.interop.ArkUIView(
name = name,
modifier = modifier,
parameter = parameter,
update = update,
background = background,
updater = updater,
onCreate = onCreate,
onRelease = onRelease,
interactive = interactive,
adaptiveParams = adaptiveParams,
tag = tag,
container = container,
)
package com.dong.test1
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
@Composable
internal fun InteropListNested() {
LazyColumn(Modifier.fillMaxSize()) {
items(20) { index ->
when {
index == 3 -> {
// Nested Vertical List (ArkUI)
ArkUIView(
name = "verticalList",
modifier = Modifier.fillMaxWidth().height(300.dp).background(Color.LightGray),
parameter = js { }
)
}
index == 7 -> {
// Horizontal List (ArkUI) - assuming horizontalList exists and works similar
ArkUIView(
name = "horizontalList",
modifier = Modifier.fillMaxWidth().height(150.dp).background(Color.LightGray),
parameter = js { }
)
}
index % 3 == 0 -> {
// Button (ArkUI)
ArkUIView(
name = "button",
modifier = Modifier.fillMaxWidth().height(60.dp),
parameter = js {
"text"("ArkUI Button $index")
"backgroundColor"("#FF0000FF")
}
)
}
else -> {
// Compose Text
Text("Compose Item $index", Modifier.padding(16.dp))
}
}
}
}
}
package com.dong.test1
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
@Composable
internal fun InteropListSimple() {
Box {
Column(Modifier.background(Color.LightGray).fillMaxSize()) {
LazyColumn(Modifier.background(Color.Red).fillMaxSize()) {
items(80) { index ->
Column {
ArkUIView(
name = "label",
modifier = Modifier.width(250.dp).height(100.dp),
parameter = js {
"text"("ArkUI Button $index")
"backgroundColor"("#FF0000FF")
},
)
Button({
println("Compose Button $index clicked")
}, modifier = Modifier.height(30.dp).fillMaxWidth()) {
Text("Compose Button $index")
}
}
}
}
}
}
}
package com.dong.test1
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
@Composable
internal fun InteropRenderOrder() {
var interLayer by remember { mutableStateOf(false) }
Column {
Box {
ArkUIView(
"layer", Modifier.width(400.dp).height(300.dp),
js {
"text"("1")
"backgroundColor"("#FF0000FF")
},
)
ArkUIView(
"layer", Modifier.width(350.dp).height(250.dp),
js {
"text"("2")
"backgroundColor"("#FF00FF00")
},
)
if (interLayer) {
ArkUIView(
"layer", Modifier.width(300.dp).height(200.dp),
js {
"text"("3")
"backgroundColor"("#FFFF0000")
},
)
}
ArkUIView(
"layer", Modifier.width(250.dp).height(150.dp),
js {
"text"("4")
"backgroundColor"("#FF00FFFF")
},
)
ArkUIView(
"layer", Modifier.width(200.dp).height(100.dp),
js {
"text"("5")
"backgroundColor"("#FFFFFF00")
},
)
}
Button({ interLayer = !interLayer }) {
Text("Show / Hide")
}
}
}
package com.dong.test1
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.napi.asString
import androidx.compose.ui.napi.js
import androidx.compose.ui.unit.dp
import kotlinx.cinterop.ExperimentalForeignApi
@OptIn(ExperimentalForeignApi::class)
@Composable
internal fun InteropTextInput() {
Column(
Modifier
.fillMaxWidth()
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.padding(30.dp)
) {
var inputText by remember { mutableStateOf("混排状态变量双向通信 输入文本...") }
val state = remember(inputText) {
js { "text"(inputText) }
}
ArkUIView(
name = "textInput",
modifier = Modifier.width(450.dp).wrapContentHeight(),
parameter = state,
update = {
inputText = it["text"].asString().toString()
}
)
Spacer(modifier = Modifier.height(50.dp))
Text(text = "Compose组件更新:", color = Color.Gray)
Text(
text = inputText,
modifier = Modifier.fillMaxWidth()
.border(width = 1.dp, color = Color.Gray)
.padding(10.dp)
)
Button(onClick = { inputText += "[文本]" }) {
Text("Append Text")
}
}
}
package com.dong.test1
import kotlinx.atomicfu.AtomicBoolean
import kotlinx.atomicfu.atomic
class LogControllerImpl : LogController {
private val _isRunning = atomic(true)
override val isRunning: Boolean
get() = _isRunning.value
override fun stop() {
_isRunning.value = false
}
}
\ No newline at end of file
package com.dong.test1
import androidx.compose.ui.window.ComposeArkUIViewController
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.coroutines.initMainHandler
import platform.ohos.napi_env
import platform.ohos.napi_value
import kotlin.experimental.ExperimentalNativeApi
@OptIn(ExperimentalNativeApi::class, ExperimentalForeignApi::class)
@CName("MainArkUIViewController")
fun MainArkUIViewController(env: napi_env): napi_value {
initMainHandler(env)
return ComposeArkUIViewController(env) {
App()
}
}
package com.dong.test1
class OhosPlatform : Platform {
override val name: String = "HarmonyOS"
}
actual fun getPlatform(): Platform = OhosPlatform()
internal actual fun getPlatformDemoList(): List<PlatformDemoItem> = listOf(
PlatformDemoItem("interop_list_nested", "混排嵌滑"),
PlatformDemoItem("interop_list_simple", "混排列表"),
PlatformDemoItem("interop_render_order", "混排层级"),
PlatformDemoItem("interop_text_input", "混排输入"),
)
@androidx.compose.runtime.Composable
internal actual fun PlatformDemo(id: String) {
when (id) {
"interop_list_nested" -> InteropListNested()
"interop_list_simple" -> InteropListSimple()
"interop_render_order" -> InteropRenderOrder()
"interop_text_input" -> InteropTextInput()
}
}
package com.dong.test1
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import platform.PerformanceAnalysisKit.HiLog.*
actual fun startLog(speed: Int, onLogGenerated: ((Int) -> Unit)?, onTimerUpdated: ((Long) -> Unit)?): LogController {
val controller = LogControllerImpl()
// 启动协程在后台执行日志生成
GlobalScope.launch {
generateLogs(speed, onLogGenerated, onTimerUpdated, controller)
}
return controller
}
actual fun createTimer(): TimerController {
return TimerControllerImpl()
}
private suspend fun generateLogs(speed: Int, onLogGenerated: ((Int) -> Unit)?, onTimerUpdated: ((Long) -> Unit)?, controller: LogControllerImpl) {
val startTime = getTimeMillis()
var count = 0
// 发送开始日志 (fatal级别)
hiLogPrintMsg(
type = 0u,
level = 4u, // FATAL level
domain = 0x1234u,
tag = "LogGenerator",
message = "日志生成开始,间隔 ${speed} 毫秒,手动停止模式"
)
// 手动停止模式:持续运行直到用户停止
while (controller.isRunning) {
val currentTime = getTimeMillis()
val elapsedSeconds = (currentTime - startTime) / 1000
// 每秒更新一次计时器显示
if (elapsedSeconds > count) {
onTimerUpdated?.invoke(elapsedSeconds)
}
// 发送普通info日志
hiLogPrintMsg(
type = 0u,
level = 1u, // INFO level
domain = 0x1234u,
tag = "LogGenerator",
message = "生成第 ${++count} 条日志,运行时间: $elapsedSeconds 秒"
)
// 通知UI更新计数
onLogGenerated?.invoke(count)
// 等待指定间隔
kotlinx.coroutines.delay(speed.toLong())
}
// 发送结束日志
val finalTime = (getTimeMillis() - startTime) / 1000
hiLogPrintMsg(
type = 0u,
level = 4u, // FATAL level
domain = 0x1234u,
tag = "LogGenerator",
message = "日志生成手动停止,总运行时间: $finalTime 秒,总共生成: $count 条日志"
)
}
// 获取当前时间戳(毫秒)
private fun getTimeMillis(): Long {
return kotlin.time.TimeSource.Monotonic.markNow().elapsedNow().inWholeMilliseconds
}
@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class, kotlin.experimental.ExperimentalNativeApi::class)
@CName("hiLogPrintMsg")
fun hiLogPrintMsg(type: UInt, level: UInt, domain: UInt, tag: String, message: String): Int {
return try {
OH_LOG_PrintMsg(type, level, domain, tag, message)
} catch (_: Throwable) {
-1
}
}
\ No newline at end of file
package com.dong.test1
import kotlinx.atomicfu.AtomicBoolean
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
class TimerControllerImpl : TimerController {
private val _isRunning = atomic(false)
private val _elapsedTime = atomic(0L)
private var timerJob: Job? = null
private val scope = CoroutineScope(Dispatchers.Default)
override val isRunning: Boolean
get() = _isRunning.value
override val elapsedTime: Long
get() = _elapsedTime.value
override fun start() {
if (!_isRunning.value) {
_isRunning.value = true
startTimer()
}
}
override fun stop() {
if (_isRunning.value) {
_isRunning.value = false
timerJob?.cancel()
}
}
override fun reset() {
stop()
_elapsedTime.value = 0L
}
private fun startTimer() {
timerJob = scope.launch {
while (isRunning) {
delay(1000) // 每秒递增1
_elapsedTime.incrementAndGet()
}
}
}
}
\ No newline at end of file
import { LogGenerator } from '../utils/LogGenerator';
import { LogManager } from '../utils/LogManager';
@Entry
@Component
struct Index {
@State message: string = '日志生成器';
@State isGenerating: boolean = false;
@State logCount: number = 0;
@State selectedInterval: number = 1000;
@State batchCount: number = 100;
private logGenerator: LogGenerator = LogGenerator.getInstance();
aboutToAppear(): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '应用启动,初始化日志生成器');
}
build() {
Scroll() {
Column({ space: 20 }) {
// 标题
Text(this.message)
.fontSize(32)
.fontWeight(FontWeight.Bold)
.fontColor('#1890FF')
.margin({ top: 20 })
// 状态显示
Row() {
Text(`运行状态: ${this.isGenerating ? '运行中' : '已停止'}`)
.fontSize(18)
.fontColor(this.isGenerating ? '#52C41A' : '#FF4D4F')
}
.width('90%')
.justifyContent(FlexAlign.Start)
// 控制按钮区域
Column({ space: 15 }) {
Text('实时日志生成')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
// 启动/停止按钮
Button(this.isGenerating ? '停止生成' : '开始生成')
.type(ButtonType.Normal)
.backgroundColor(this.isGenerating ? '#FF4D4F' : '#52C41A')
.width('80%')
.height(50)
.fontSize(18)
.onClick(() => {
this.toggleGeneration();
})
// 间隔时间选择
Row({ space: 10 }) {
Text('间隔:')
.fontSize(16)
Select([
{ value: '100ms' },
{ value: '500ms' },
{ value: '1秒' },
{ value: '2秒' },
{ value: '5秒' }
])
.value('1秒')
.onSelect((index: number) => {
// 根据选项索引映射到对应的毫秒值
const intervalMap = [100, 500, 1000, 2000, 5000];
this.selectedInterval = intervalMap[index] || 1000;
LogManager.info(LogManager.DOMAIN_UI, LogManager.TAG_UI,
'设置日志生成间隔为: %{public}d ms', this.selectedInterval);
})
}
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
// 批量日志生成
Column({ space: 15 }) {
Text('批量日志生成')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
// 数量输入
Row({ space: 10 }) {
Text('数量:')
.fontSize(16)
TextInput({ placeholder: '输入日志数量', text: this.batchCount.toString() })
.onChange((value: string) => {
const num = parseInt(value);
if (!isNaN(num) && num > 0) {
this.batchCount = num;
}
})
.width(120)
.type(InputType.Number)
}
// 批量生成按钮
Row({ space: 10 }) {
Button('生成Info日志')
.backgroundColor('#1890FF')
.onClick(() => {
this.generateBatchLogs('info');
})
Button('生成Error日志')
.backgroundColor('#FF4D4F')
.onClick(() => {
this.generateBatchLogs('error');
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
// 单次日志生成
Column({ space: 15 }) {
Text('单次日志测试')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
Grid() {
ForEach([
'应用日志',
'网络日志',
'数据库日志',
'文件日志',
'系统日志',
'全部类型',
'格式异常',
'边界测试'
], (item: string) => {
GridItem() {
Button(item)
.backgroundColor(item.includes('异常') || item.includes('边界') ? '#FF7A45' : '#722ED1')
.width('90%')
.height(45)
.fontSize(14)
.onClick(() => {
this.handleGridItemClick(item);
})
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr') // 4列布局
.rowsTemplate('1fr 1fr') // 2行布局
.width('100%')
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
// 统计信息
Column({ space: 10 }) {
Text('统计信息')
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor('#333')
Row() {
Text(`累计生成: ${this.logCount} 条日志`)
.fontSize(16)
.fontColor('#666')
}
Button('清空统计')
.backgroundColor('#FAAD14')
.width('60%')
.onClick(() => {
this.logCount = 0;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '统计信息已清空');
})
}
.width('90%')
.padding(20)
.backgroundColor('#F5F5F5')
.borderRadius(10)
.margin({ bottom: 30 })
}
.width('100%')
.padding({ left: 20, right: 20 })
}
.height('100%')
.width('100%')
}
/**
* 切换日志生成状态
*/
private toggleGeneration(): void {
if (this.isGenerating) {
this.logGenerator.stopContinuousLogging();
this.isGenerating = false;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '手动停止日志生成');
} else {
this.logGenerator.startContinuousLogging(this.selectedInterval);
this.isGenerating = true;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'手动启动日志生成,间隔: %{public}d ms', this.selectedInterval);
}
}
/**
* 生成批量日志
*/
private generateBatchLogs(level: 'info' | 'error'): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'开始批量生成%{public}s日志,数量: %{public}d', level, this.batchCount);
this.logGenerator.generateBatchLogs(this.batchCount, level);
this.logCount += this.batchCount;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'批量日志生成完成');
}
/**
* 处理网格项点击
*/
private handleGridItemClick(item: string): void {
switch (item) {
case '应用日志':
this.logGenerator.generateAppLogs();
this.logCount += 1;
break;
case '网络日志':
this.logGenerator.generateNetworkLogs();
this.logCount += 1;
break;
case '数据库日志':
this.logGenerator.generateDatabaseLogs();
this.logCount += 1;
break;
case '文件日志':
this.logGenerator.generateFileLogs();
this.logCount += 1;
break;
case '系统日志':
this.logGenerator.generateSystemLogs();
this.logCount += 1;
break;
case '全部类型':
this.generateAllTypesOnce();
break;
case '格式异常':
LogManager.warn(LogManager.DOMAIN_APP, LogManager.TAG_APP, '格式异常测试功能暂未实现');
// this.logGenerator.generateAbnormalFormatLogs();
this.logCount += 1;
break;
case '边界测试':
LogManager.warn(LogManager.DOMAIN_APP, LogManager.TAG_APP, '边界测试功能暂未实现');
// this.logGenerator.generateBoundaryLogs();
this.logCount += 1;
break;
}
}
/**
* 生成所有类型日志一次
*/
private generateAllTypesOnce(): void {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '开始生成所有类型日志示例');
this.logGenerator.generateAppLogs();
this.logGenerator.generateNetworkLogs();
this.logGenerator.generateDatabaseLogs();
this.logGenerator.generateFileLogs();
this.logGenerator.generateSystemLogs();
this.logCount += 5;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '所有类型日志生成完成');
}
}
\ No newline at end of file
import { LogManager } from './LogManager';
/**
* 日志生成器类
* 模拟各种业务场景下的日志输出
*/
export class LogGenerator {
private static instance: LogGenerator | null = null;
private isGenerating: boolean = false;
private intervalId: number | null = null;
// 模拟数据
private static readonly USERS = ['张三', '李四', '王五', '赵六', '钱七'];
private static readonly ACTIONS = ['登录', '登出', '查询', '更新', '删除', '创建'];
private static readonly STATUS_CODES = [200, 404, 500, 403, 401];
private static readonly FILE_NAMES = ['config.json', 'data.txt', 'image.png', 'document.pdf', 'log.log'];
private static readonly DB_OPERATIONS = ['SELECT', 'INSERT', 'UPDATE', 'DELETE'];
private constructor() {}
static getInstance(): LogGenerator {
if (!LogGenerator.instance) {
LogGenerator.instance = new LogGenerator();
}
return LogGenerator.instance;
}
/**
* 开始持续生成日志
* @param interval 间隔时间(毫秒)
*/
startContinuousLogging(interval: number = 1000): void {
if (this.isGenerating) {
LogManager.warn(LogManager.DOMAIN_APP, LogManager.TAG_APP, '日志生成已在运行中');
return;
}
this.isGenerating = true;
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '开始持续生成日志,间隔: %{public}d ms', interval);
this.intervalId = setInterval(() => {
this.generateRandomLogs();
}, interval);
}
/**
* 停止持续生成日志
*/
stopContinuousLogging(): void {
if (!this.isGenerating) {
LogManager.warn(LogManager.DOMAIN_APP, LogManager.TAG_APP, '日志生成未在运行');
return;
}
this.isGenerating = false;
if (this.intervalId !== null) {
clearInterval(this.intervalId);
this.intervalId = null;
}
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP, '停止持续生成日志');
}
/**
* 生成随机日志
*/
private generateRandomLogs(): void {
const logTypes = [
() => this.generateAppLogs(),
() => this.generateNetworkLogs(),
() => this.generateDatabaseLogs(),
() => this.generateFileLogs(),
() => this.generateSystemLogs()
];
// 随机选择1-3种日志类型生成
const count = Math.floor(Math.random() * 3) + 1;
const selectedTypes = this.shuffleArray(logTypes).slice(0, count);
selectedTypes.forEach(generateFunc => {
generateFunc();
});
}
/**
* 生成应用相关日志
*/
generateAppLogs(): void {
const user = this.getRandomItem(LogGenerator.USERS);
const action = this.getRandomItem(LogGenerator.ACTIONS);
const success = Math.random() > 0.2; // 80%成功率
if (success) {
LogManager.info(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'用户%{public}s执行%{public}s操作成功', user, action);
} else {
LogManager.error(LogManager.DOMAIN_APP, LogManager.TAG_APP,
'用户%{public}s执行%{public}s操作失败', user, action);
}
}
/**
* 生成网络相关日志
*/
generateNetworkLogs(): void {
const statusCode = this.getRandomItem(LogGenerator.STATUS_CODES);
const url = `https://api.example.com/data/${Math.floor(Math.random() * 1000)}`;
if (statusCode === 200) {
LogManager.info(LogManager.DOMAIN_NETWORK, LogManager.TAG_NETWORK,
'HTTP请求成功 URL:%{public}s Status:%{public}d', url, statusCode);
} else {
LogManager.error(LogManager.DOMAIN_NETWORK, LogManager.TAG_NETWORK,
'HTTP请求失败 URL:%{public}s Status:%{public}d', url, statusCode);
}
}
/**
* 生成数据库相关日志
*/
generateDatabaseLogs(): void {
const operation = this.getRandomItem(LogGenerator.DB_OPERATIONS);
const tableName = `table_${Math.floor(Math.random() * 10)}`;
const recordCount = Math.floor(Math.random() * 100) + 1;
const duration = Math.floor(Math.random() * 500) + 10; // 10-510ms
LogManager.info(LogManager.DOMAIN_DATABASE, LogManager.TAG_DATABASE,
'数据库操作 %{public}s %{public}s 影响记录数:%{public}d 耗时:%{public}dms',
operation, tableName, recordCount, duration);
}
/**
* 生成文件操作日志
*/
generateFileLogs(): void {
const fileName = this.getRandomItem(LogGenerator.FILE_NAMES);
const operation = Math.random() > 0.5 ? '读取' : '写入';
const fileSize = Math.floor(Math.random() * 10240) + 1024; // 1KB-10KB
const success = Math.random() > 0.1; // 90%成功率
if (success) {
LogManager.info(LogManager.DOMAIN_FILE, LogManager.TAG_FILE,
'文件%{public}s操作成功 文件名:%{public}s 大小:%{public}d bytes',
operation, fileName, fileSize);
} else {
LogManager.error(LogManager.DOMAIN_FILE, LogManager.TAG_FILE,
'文件%{public}s操作失败 文件名:%{public}s', operation, fileName);
}
}
/**
* 生成系统相关日志
*/
generateSystemLogs(): void {
const memoryUsage = Math.floor(Math.random() * 80) + 10; // 10%-90%
const cpuUsage = Math.floor(Math.random() * 90) + 5; // 5%-95%
const batteryLevel = Math.floor(Math.random() * 100); // 0%-100%
LogManager.info(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'系统状态监控 内存使用率:%{public}d%% CPU使用率:%{public}d%% 电池电量:%{public}d%%',
memoryUsage, cpuUsage, batteryLevel);
// 当内存使用超过80%时输出警告
if (memoryUsage > 80) {
LogManager.warn(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'内存使用率过高:%{public}d%%,建议清理缓存', memoryUsage);
}
// 当电池低于20%时输出警告
if (batteryLevel < 20) {
LogManager.warn(LogManager.DOMAIN_SYSTEM, LogManager.TAG_SYSTEM,
'电池电量低:%{public}d%%,请及时充电', batteryLevel);
}
}
/**
* 批量生成指定数量的日志
* @param count 日志数量
* @param level 日志级别
*/
generateBatchLogs(count: number, level: 'debug' | 'info' | 'warn' | 'error' | 'fatal' = 'info'): void {
LogManager.batchLog(level, LogManager.DOMAIN_APP, LogManager.TAG_APP,
'批量日志生成 测试消息', count);
}
/**
* 从数组中随机获取一项
*/
private getRandomItem<T>(array: T[]): T {
return array[Math.floor(Math.random() * array.length)];
}
/**
* 数组随机排序
*/
private shuffleArray<T>(array: T[]): T[] {
const newArray = [...array];
for (let i = newArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
const temp = newArray[i];
newArray[i] = newArray[j];
newArray[j] = temp;
}
return newArray;
}
/**
* 获取当前生成状态
*/
isRunning(): boolean {
return this.isGenerating;
}
}
\ No newline at end of file
import { hilog } from '@kit.PerformanceAnalysisKit';
/**
* 日志管理工具类
* 提供统一的日志输出接口,支持不同级别和域的日志记录
*/
export class LogManager {
// 日志域定义
static readonly DOMAIN_APP = 0x0001;
static readonly DOMAIN_NETWORK = 0x0002;
static readonly DOMAIN_DATABASE = 0x0003;
static readonly DOMAIN_FILE = 0x0004;
static readonly DOMAIN_UI = 0x0005;
static readonly DOMAIN_SYSTEM = 0x0006;
// 标签定义
static readonly TAG_APP = 'BigLogApp';
static readonly TAG_NETWORK = 'NetworkService';
static readonly TAG_DATABASE = 'DatabaseOps';
static readonly TAG_FILE = 'FileHandler';
static readonly TAG_UI = 'UIComponent';
static readonly TAG_SYSTEM = 'SystemService';
/**
* 输出调试日志
* @param domain 日志域
* @param tag 标签
* @param format 格式化字符串
* @param args 参数
*/
static debug(domain: number, tag: string, format: string, ...args: (string | number | boolean)[]): void {
hilog.debug(domain, tag, format, ...args);
}
/**
* 输出信息日志
* @param domain 日志域
* @param tag 标签
* @param format 格式化字符串
* @param args 参数
*/
static info(domain: number, tag: string, format: string, ...args: (string | number | boolean)[]): void {
hilog.info(domain, tag, format, ...args);
}
/**
* 输出警告日志
* @param domain 日志域
* @param tag 标签
* @param format 格式化字符串
* @param args 参数
*/
static warn(domain: number, tag: string, format: string, ...args: (string | number | boolean)[]): void {
hilog.warn(domain, tag, format, ...args);
}
/**
* 输出错误日志
* @param domain 日志域
* @param tag 标签
* @param format 格式化字符串
* @param args 参数
*/
static error(domain: number, tag: string, format: string, ...args: (string | number | boolean)[]): void {
hilog.error(domain, tag, format, ...args);
}
/**
* 输出致命错误日志
* @param domain 日志域
* @param tag 标签
* @param format 格式化字符串
* @param args 参数
*/
static fatal(domain: number, tag: string, format: string, ...args: (string | number | boolean)[]): void {
hilog.fatal(domain, tag, format, ...args);
}
/**
* 批量输出相同类型日志
* @param level 日志级别
* @param domain 日志域
* @param tag 标签
* @param format 格式化字符串
* @param count 输出次数
* @param args 参数
*/
static batchLog(level: 'debug' | 'info' | 'warn' | 'error' | 'fatal',
domain: number,
tag: string,
format: string,
count: number,
...args: (string | number | boolean)[]): void {
for (let i = 0; i < count; i++) {
const timestamp = Date.now();
const message = `${format} [Batch:${i+1}/${count}] [Time:${timestamp}]`;
switch (level) {
case 'debug':
LogManager.debug(domain, tag, message, ...args);
break;
case 'info':
LogManager.info(domain, tag, message, ...args);
break;
case 'warn':
LogManager.warn(domain, tag, message, ...args);
break;
case 'error':
LogManager.error(domain, tag, message, ...args);
break;
case 'fatal':
LogManager.fatal(domain, tag, message, ...args);
break;
}
}
}
}
\ No newline at end of file
{
}
\ No newline at end of file
#Kotlin
kotlin.code.style=official
kotlin.daemon.jvmargs=-Xmx3072M
#Gradle
org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8
org.gradle.configuration-cache=true
org.gradle.caching=true
#Android
android.nonTransitiveRClass=true
android.useAndroidX=true
kotlin.native.cacheKind=none
org.gradle.internal.http.connectionTimeout=100000
org.gradle.internal.http.socketTimeout=100000
[versions]
agp = "8.11.2"
android-compileSdk = "36"
android-minSdk = "24"
android-targetSdk = "36"
androidx-activity = "1.12.2"
androidx-appcompat = "1.7.1"
androidx-constraintlayout = "2.2.1"
androidx-core = "1.17.0"
androidx-espresso = "3.7.0"
androidx-lifecycle = "2.9.6"
androidx-material = "1.12.0"
androidx-testExt = "1.3.0"
androidx-collection = "1.4.5"
compose = "1.9.4"
composeMultiplatform = "1.9.2-ez-001"
junit = "4.13.2"
kotlin = "2.2.21-ez-001"
kotlinx-coroutines = "1.8.0-KBA-001"
atomicFu = "0.23.2-KBA-001"
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-testJunit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
junit = { module = "junit:junit", version.ref = "junit" }
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-testExt-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-testExt" }
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
androidx-lifecycle-viewmodelCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
androidx-collection = { module = "androidx.collection:collection", version.ref = "androidx-collection" }
compose-multiplatform-export = { module = "org.jetbrains.compose.export:export", version.ref = "composeMultiplatform" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" }
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
atomicFu = { module = "org.jetbrains.kotlinx:atomicfu", version.ref = "atomicFu" }
# AndroidX compose, only used by android target.
compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" }
compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose" }
compose-material = { module = "androidx.compose.material:material", version.ref = "compose" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
androidLibrary = { id = "com.android.library", version.ref = "agp" }
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
cocoapods = { id = "org.jetbrains.kotlin.native.cocoapods", version.ref = "kotlin" }
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
/node_modules
/oh_modules
/local.properties
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test
/.appanalyzer
{
"app": {
"bundleName": "com.eazytec.bigLog",
"bundleName": "com.example.harmonyapp",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:layered_image",
"label": "$string:app_name"
"label": "$string:app_name",
"hwasanEnabled": true
}
}
......@@ -2,7 +2,7 @@
"string": [
{
"name": "app_name",
"value": "bigLog"
"value": "harmonyApp"
}
]
}
......@@ -4,4 +4,4 @@
"background" : "$media:background",
"foreground" : "$media:foreground"
}
}
\ No newline at end of file
}
{
"app": {
"signingConfigs": [],
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "/Users/dongsq/.ohos/config/default_harmonyApp_RDQoPiSVSDNnhmxkpXEZJlLeD-XFA9Y_iTtbP5uZMJc=.cer",
"keyAlias": "debugKey",
"keyPassword": "0000001BBE86A252D0F5BB9976E3647CF969BB82EA7F26ECAC10D740BB4690FD5B890CA931A867D0AF1A81",
"profile": "/Users/dongsq/.ohos/config/default_harmonyApp_RDQoPiSVSDNnhmxkpXEZJlLeD-XFA9Y_iTtbP5uZMJc=.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "/Users/dongsq/.ohos/config/default_harmonyApp_RDQoPiSVSDNnhmxkpXEZJlLeD-XFA9Y_iTtbP5uZMJc=.p12",
"storePassword": "0000001B7C47D2660DBE110429482505A0F62F11A03D847FE54910C92673D7B7704C983FCEA484078BBECB"
}
}
],
"products": [
{
"name": "default",
......@@ -9,6 +23,7 @@
"compatibleSdkVersion": "6.0.0(20)",
"runtimeOS": "HarmonyOS",
"buildOption": {
"nativeCompiler": "BiSheng",
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
......@@ -39,4 +54,4 @@
]
}
]
}
\ No newline at end of file
}
......@@ -29,4 +29,4 @@
"@security/no-unsafe-dh-key": "error",
"@security/no-unsafe-3des": "error"
}
}
\ No newline at end of file
}
......@@ -3,4 +3,4 @@
/.preview
/build
/.cxx
/.test
\ No newline at end of file
/.test
......@@ -5,7 +5,12 @@
"copyCodeResource": {
"enable": false
}
}
},
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "-DOHOS_ENABLE_HWASAN=ON",
"cppFlags": "",
},
},
"buildOptionSet": [
{
......@@ -19,6 +24,12 @@
]
}
}
},
"nativeLib": {
"debugSymbol": {
"strip": true,
"exclude": []
}
}
},
],
......@@ -30,4 +41,4 @@
"name": "ohosTest",
}
]
}
\ No newline at end of file
}
......@@ -3,4 +3,4 @@ import { hapTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
}
\ No newline at end of file
}
......@@ -20,4 +20,4 @@
-enable-property-obfuscation
-enable-toplevel-obfuscation
-enable-filename-obfuscation
-enable-export-obfuscation
\ No newline at end of file
-enable-export-obfuscation
{
"meta": {
"stableOrder": true,
"enableUnifiedLockfile": false
},
"lockfileVersion": 3,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"compose@libs/compose.har": "compose@libs/compose.har",
"libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils": "libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils",
"libentry.so@src/main/cpp/types/libentry": "libentry.so@src/main/cpp/types/libentry",
"libskikobridge.so@../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge": "libskikobridge.so@../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge",
"skikobridge@libs/skikobridge.har": "skikobridge@libs/skikobridge.har"
},
"packages": {
"compose@libs/compose.har": {
"name": "compose",
"version": "1.0.0",
"resolved": "libs/compose.har",
"registryType": "local",
"dependencies": {
"libcompose_arkui_utils.so": "file:./src/main/cpp/types/libcompose_arkui_utils"
}
},
"libcompose_arkui_utils.so@../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils": {
"name": "libcompose_arkui_utils.so",
"version": "1.0.0",
"resolved": "../oh_modules/.ohpm/compose@h5xuwfo6vqe0fkvy6j77dndaihorlv4+5iu+h2krdy8=/oh_modules/compose/src/main/cpp/types/libcompose_arkui_utils",
"registryType": "local"
},
"libentry.so@src/main/cpp/types/libentry": {
"name": "libentry.so",
"version": "1.0.0",
"resolved": "src/main/cpp/types/libentry",
"registryType": "local"
},
"libskikobridge.so@../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge": {
"name": "libskikobridge.so",
"version": "0.0.0",
"resolved": "../oh_modules/.ohpm/skikobridge@y2fnhawohlg+q+eadhgpdonzjxt7nzphn6xzlfx6ile=/oh_modules/skikobridge/src/main/cpp/types/libskikobridge",
"registryType": "local"
},
"skikobridge@libs/skikobridge.har": {
"name": "skikobridge",
"version": "1.0.0",
"resolved": "libs/skikobridge.har",
"registryType": "local",
"dependencies": {
"libskikobridge.so": "file:./src/main/cpp/types/libskikobridge"
}
}
}
}
\ No newline at end of file
......@@ -5,6 +5,11 @@
"main": "",
"author": "",
"license": "",
"dependencies": {}
"dependencies": {
"libentry.so": "file:./src/main/cpp/types/libentry",
// 添加 compose.har 依赖
"compose": "file:./libs/compose.har",
// 添加 skikobridge.har 依赖
"skikobridge": "file:./libs/skikobridge.har"
}
}
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(harmonyApp)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
find_package(skikobridge)
add_library(entry SHARED napi_init.cpp)
# Link against ComposeApp shared library to resolve exported symbols
add_library(ComposeApp SHARED IMPORTED)
target_link_libraries(entry PUBLIC libace_napi.z.so)
target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
target_link_libraries(entry PUBLIC libdeviceinfo_ndk.z.so)
target_link_libraries(entry PUBLIC librawfile.z.so)
#target_link_libraries(entry PUBLIC libicu.so)
target_link_libraries(entry PUBLIC skikobridge::skikobridge)
set_target_properties(ComposeApp PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/arm64-v8a/libkn.so"
)
target_link_libraries(entry PUBLIC ComposeApp)
target_link_libraries(entry PUBLIC ${EGL-lib} ${GLES-lib} ${hilog-lib} ${libace-lib} ${libnapi-lib} ${libuv-lib} libc++_shared.so)
#ifndef KONAN_LIBKN_H
#define KONAN_LIBKN_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
typedef bool libkn_KBoolean;
#else
typedef _Bool libkn_KBoolean;
#endif
typedef unsigned short libkn_KChar;
typedef signed char libkn_KByte;
typedef short libkn_KShort;
typedef int libkn_KInt;
typedef long long libkn_KLong;
typedef unsigned char libkn_KUByte;
typedef unsigned short libkn_KUShort;
typedef unsigned int libkn_KUInt;
typedef unsigned long long libkn_KULong;
typedef float libkn_KFloat;
typedef double libkn_KDouble;
typedef float __attribute__ ((__vector_size__ (16))) libkn_KVector128;
typedef void* libkn_KNativePtr;
struct libkn_KType;
typedef struct libkn_KType libkn_KType;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Byte;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Short;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Int;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Long;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Float;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Double;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Char;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Boolean;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Unit;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_UByte;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_UShort;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_UInt;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_ULong;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_Platform;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_TimerController;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Function1;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_LogController;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_collections_List;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_collections_Map;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_ComposeGroup;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_ComposeGroup_Ui;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_ComposeGroup_Foundation;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_ComposeGroup_Material;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_ComposeGroup_Benchmark;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_ComposeGroup_Platform;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_ComponentDemo;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_kotlin_Any;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_Page;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_Page_Home;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_navigation_Page_Detail;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_Greeting;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_LogControllerImpl;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_OhosPlatform;
typedef struct {
libkn_KNativePtr pinned;
} libkn_kref_com_dong_test1_TimerControllerImpl;
extern void* MainArkUIViewController(void* env);
extern libkn_KInt hiLogPrintMsg(libkn_KUInt type, libkn_KUInt level, libkn_KUInt domain, const char* tag, const char* message);
extern void androidx_compose_ui_arkui_ArkUIViewController_aboutToAppear(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_aboutToDisappear(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_cancelSyncRefresh(void* controllerRef, libkn_KInt refreshId);
extern void androidx_compose_ui_arkui_ArkUIViewController_dispatchHoverEvent(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_dispatchMouseEvent(void* controllerRef);
extern libkn_KBoolean androidx_compose_ui_arkui_ArkUIViewController_dispatchTouchEvent(void* controllerRef, void* nativeTouchEvent, libkn_KBoolean ignoreInteropView);
extern const char* androidx_compose_ui_arkui_ArkUIViewController_getId(void* controllerRef);
extern void* androidx_compose_ui_arkui_ArkUIViewController_getXComponentRender(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_keyboardWillHide(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_keyboardWillShow(void* controllerRef, libkn_KFloat keyboardHeight);
extern libkn_KBoolean androidx_compose_ui_arkui_ArkUIViewController_onBackPress(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onFinalize(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onFocusEvent(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onFrame(void* controllerRef, libkn_KLong timestamp, libkn_KLong targetTimestamp);
extern void androidx_compose_ui_arkui_ArkUIViewController_onKeyEvent(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onPageHide(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onPageShow(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onSurfaceChanged(void* controllerRef, libkn_KInt width, libkn_KInt height);
extern void androidx_compose_ui_arkui_ArkUIViewController_onSurfaceCreated(void* controllerRef, void* xcomponentPtr, libkn_KInt width, libkn_KInt height);
extern void androidx_compose_ui_arkui_ArkUIViewController_onSurfaceDestroyed(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onSurfaceHide(void* controllerRef);
extern void androidx_compose_ui_arkui_ArkUIViewController_onSurfaceShow(void* controllerRef);
extern libkn_KInt androidx_compose_ui_arkui_ArkUIViewController_requestSyncRefresh(void* controllerRef);
extern const char* androidx_compose_ui_arkui_ArkUIViewController_sendMessage(void* controllerRef, const char* type, const char* message);
extern void androidx_compose_ui_arkui_ArkUIViewController_setContext(void* controllerRef, void* context);
extern void androidx_compose_ui_arkui_ArkUIViewController_setEnv(void* controllerRef, void* env);
extern void androidx_compose_ui_arkui_ArkUIViewController_setId(void* controllerRef, const char* id);
extern void androidx_compose_ui_arkui_ArkUIViewController_setMessenger(void* controllerRef, void* messenger);
extern void androidx_compose_ui_arkui_ArkUIViewController_setRootView(void* controllerRef, void* backRootView, void* foreRootView, void* touchableRootView);
extern void androidx_compose_ui_arkui_ArkUIViewController_setUIContext(void* controllerRef, void* uiContext);
extern void androidx_compose_ui_arkui_ArkUIViewController_setXComponentRender(void* controllerRef, void* render);
extern void androidx_compose_ui_arkui_init(void* env, void* exports);
typedef struct {
/* Service functions. */
void (*DisposeStablePointer)(libkn_KNativePtr ptr);
void (*DisposeString)(const char* string);
libkn_KBoolean (*IsInstance)(libkn_KNativePtr ref, const libkn_KType* type);
libkn_kref_kotlin_Byte (*createNullableByte)(libkn_KByte);
libkn_KByte (*getNonNullValueOfByte)(libkn_kref_kotlin_Byte);
libkn_kref_kotlin_Short (*createNullableShort)(libkn_KShort);
libkn_KShort (*getNonNullValueOfShort)(libkn_kref_kotlin_Short);
libkn_kref_kotlin_Int (*createNullableInt)(libkn_KInt);
libkn_KInt (*getNonNullValueOfInt)(libkn_kref_kotlin_Int);
libkn_kref_kotlin_Long (*createNullableLong)(libkn_KLong);
libkn_KLong (*getNonNullValueOfLong)(libkn_kref_kotlin_Long);
libkn_kref_kotlin_Float (*createNullableFloat)(libkn_KFloat);
libkn_KFloat (*getNonNullValueOfFloat)(libkn_kref_kotlin_Float);
libkn_kref_kotlin_Double (*createNullableDouble)(libkn_KDouble);
libkn_KDouble (*getNonNullValueOfDouble)(libkn_kref_kotlin_Double);
libkn_kref_kotlin_Char (*createNullableChar)(libkn_KChar);
libkn_KChar (*getNonNullValueOfChar)(libkn_kref_kotlin_Char);
libkn_kref_kotlin_Boolean (*createNullableBoolean)(libkn_KBoolean);
libkn_KBoolean (*getNonNullValueOfBoolean)(libkn_kref_kotlin_Boolean);
libkn_kref_kotlin_Unit (*createNullableUnit)(void);
libkn_kref_kotlin_UByte (*createNullableUByte)(libkn_KUByte);
libkn_KUByte (*getNonNullValueOfUByte)(libkn_kref_kotlin_UByte);
libkn_kref_kotlin_UShort (*createNullableUShort)(libkn_KUShort);
libkn_KUShort (*getNonNullValueOfUShort)(libkn_kref_kotlin_UShort);
libkn_kref_kotlin_UInt (*createNullableUInt)(libkn_KUInt);
libkn_KUInt (*getNonNullValueOfUInt)(libkn_kref_kotlin_UInt);
libkn_kref_kotlin_ULong (*createNullableULong)(libkn_KULong);
libkn_KULong (*getNonNullValueOfULong)(libkn_kref_kotlin_ULong);
/* User functions. */
struct {
struct {
struct {
struct {
struct {
struct {
struct {
struct {
libkn_kref_com_dong_test1_navigation_ComposeGroup (*get)(); /* enum entry for Ui. */
} Ui;
struct {
libkn_kref_com_dong_test1_navigation_ComposeGroup (*get)(); /* enum entry for Foundation. */
} Foundation;
struct {
libkn_kref_com_dong_test1_navigation_ComposeGroup (*get)(); /* enum entry for Material. */
} Material;
struct {
libkn_kref_com_dong_test1_navigation_ComposeGroup (*get)(); /* enum entry for Benchmark. */
} Benchmark;
struct {
libkn_kref_com_dong_test1_navigation_ComposeGroup (*get)(); /* enum entry for Platform. */
} Platform;
libkn_KType* (*_type)(void);
} ComposeGroup;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_test1_navigation_ComponentDemo (*ComponentDemo)(const char* id, const char* title, libkn_kref_com_dong_test1_navigation_ComposeGroup group);
libkn_kref_com_dong_test1_navigation_ComposeGroup (*get_group)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
const char* (*get_id)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
const char* (*get_title)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
const char* (*component1)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
const char* (*component2)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
libkn_kref_com_dong_test1_navigation_ComposeGroup (*component3)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
libkn_kref_com_dong_test1_navigation_ComponentDemo (*copy)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz, const char* id, const char* title, libkn_kref_com_dong_test1_navigation_ComposeGroup group);
libkn_KBoolean (*equals)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz, libkn_kref_kotlin_Any other);
libkn_KInt (*hashCode)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
const char* (*toString)(libkn_kref_com_dong_test1_navigation_ComponentDemo thiz);
} ComponentDemo;
struct {
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_test1_navigation_Page_Home (*_instance)();
libkn_KBoolean (*equals)(libkn_kref_com_dong_test1_navigation_Page_Home thiz, libkn_kref_kotlin_Any other);
libkn_KInt (*hashCode)(libkn_kref_com_dong_test1_navigation_Page_Home thiz);
const char* (*toString)(libkn_kref_com_dong_test1_navigation_Page_Home thiz);
} Home;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_test1_navigation_Page_Detail (*Detail)(libkn_kref_com_dong_test1_navigation_ComponentDemo demo);
libkn_kref_com_dong_test1_navigation_ComponentDemo (*get_demo)(libkn_kref_com_dong_test1_navigation_Page_Detail thiz);
libkn_kref_com_dong_test1_navigation_ComponentDemo (*component1)(libkn_kref_com_dong_test1_navigation_Page_Detail thiz);
libkn_kref_com_dong_test1_navigation_Page_Detail (*copy)(libkn_kref_com_dong_test1_navigation_Page_Detail thiz, libkn_kref_com_dong_test1_navigation_ComponentDemo demo);
libkn_KBoolean (*equals)(libkn_kref_com_dong_test1_navigation_Page_Detail thiz, libkn_kref_kotlin_Any other);
libkn_KInt (*hashCode)(libkn_kref_com_dong_test1_navigation_Page_Detail thiz);
const char* (*toString)(libkn_kref_com_dong_test1_navigation_Page_Detail thiz);
} Detail;
libkn_KType* (*_type)(void);
} Page;
libkn_kref_kotlin_collections_List (*get_componentDemos)();
libkn_kref_kotlin_collections_Map (*get_groupTitles)();
libkn_KInt (*com_dong_test1_navigation_ComponentDemo$stableprop_getter)();
libkn_KInt (*com_dong_test1_navigation_Page_Detail$stableprop_getter)();
libkn_KInt (*com_dong_test1_navigation_Page_Home$stableprop_getter)();
libkn_kref_kotlin_collections_Map (*demosByGroup)();
const char* (*demosJson)();
const char* (*groupTitlesJson)();
} navigation;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_test1_Greeting (*Greeting)();
const char* (*greet)(libkn_kref_com_dong_test1_Greeting thiz);
} Greeting;
struct {
libkn_KType* (*_type)(void);
libkn_KBoolean (*get_isRunning)(libkn_kref_com_dong_test1_LogController thiz);
void (*stop)(libkn_kref_com_dong_test1_LogController thiz);
} LogController;
struct {
libkn_KType* (*_type)(void);
const char* (*get_name)(libkn_kref_com_dong_test1_Platform thiz);
} Platform;
struct {
libkn_KType* (*_type)(void);
libkn_KLong (*get_elapsedTime)(libkn_kref_com_dong_test1_TimerController thiz);
libkn_KBoolean (*get_isRunning)(libkn_kref_com_dong_test1_TimerController thiz);
void (*reset)(libkn_kref_com_dong_test1_TimerController thiz);
void (*start)(libkn_kref_com_dong_test1_TimerController thiz);
void (*stop)(libkn_kref_com_dong_test1_TimerController thiz);
} TimerController;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_test1_LogControllerImpl (*LogControllerImpl)();
libkn_KBoolean (*get_isRunning)(libkn_kref_com_dong_test1_LogControllerImpl thiz);
void (*stop)(libkn_kref_com_dong_test1_LogControllerImpl thiz);
} LogControllerImpl;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_test1_OhosPlatform (*OhosPlatform)();
const char* (*get_name)(libkn_kref_com_dong_test1_OhosPlatform thiz);
} OhosPlatform;
struct {
libkn_KType* (*_type)(void);
libkn_kref_com_dong_test1_TimerControllerImpl (*TimerControllerImpl)();
libkn_KLong (*get_elapsedTime)(libkn_kref_com_dong_test1_TimerControllerImpl thiz);
libkn_KBoolean (*get_isRunning)(libkn_kref_com_dong_test1_TimerControllerImpl thiz);
void (*reset)(libkn_kref_com_dong_test1_TimerControllerImpl thiz);
void (*start)(libkn_kref_com_dong_test1_TimerControllerImpl thiz);
void (*stop)(libkn_kref_com_dong_test1_TimerControllerImpl thiz);
} TimerControllerImpl;
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter_)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter_)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter_)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter_)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter__)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter__)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter__)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter__)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter___)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter___)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter___)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter___)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter____)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter____)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter____)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter____)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter_____)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter_____)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter_____)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter_____)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter______)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter______)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter______)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter______)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter_______)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter_______)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter_______)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter_______)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter________)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter_________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter_________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter_________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter_________)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter__________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter__________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter__________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter__________)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter___________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter___________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter___________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter___________)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter____________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter____________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter____________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter____________)();
void* (*MainArkUIViewController_)(void* env);
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter_____________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter_____________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter_____________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter_____________)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter______________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter______________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter______________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter______________)();
libkn_kref_com_dong_test1_Platform (*getPlatform)();
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter_______________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter_______________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter_______________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter_______________)();
libkn_kref_com_dong_test1_TimerController (*createTimer)();
libkn_KInt (*hiLogPrintMsg_)(libkn_KUInt type, libkn_KUInt level, libkn_KUInt domain, const char* tag, const char* message);
libkn_kref_com_dong_test1_LogController (*startLog)(libkn_KInt speed, libkn_kref_kotlin_Function1 onLogGenerated, libkn_kref_kotlin_Function1 onTimerUpdated);
libkn_KInt (*com_dong_test1_Greeting$stableprop_getter________________)();
libkn_KInt (*com_dong_test1_LogControllerImpl$stableprop_getter________________)();
libkn_KInt (*com_dong_test1_OhosPlatform$stableprop_getter________________)();
libkn_KInt (*com_dong_test1_TimerControllerImpl$stableprop_getter________________)();
} test1;
} dong;
} com;
struct {
struct {
struct {
struct {
struct {
void (*_Export_ArkUIViewController_aboutToAppear)(void* controllerRef);
void (*_Export_ArkUIViewController_aboutToDisappear)(void* controllerRef);
void (*_Export_ArkUIViewController_cancelSyncRefresh)(void* controllerRef, libkn_KInt refreshId);
void (*_Export_ArkUIViewController_dispatchHoverEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_dispatchMouseEvent)(void* controllerRef);
libkn_KBoolean (*_Export_ArkUIViewController_dispatchTouchEvent)(void* controllerRef, void* nativeTouchEvent, libkn_KBoolean ignoreInteropView);
const char* (*_Export_ArkUIViewController_getId)(void* controllerRef);
void* (*_Export_ArkUIViewController_getXComponentRender)(void* controllerRef);
void (*_Export_ArkUIViewController_keyboardWillHide)(void* controllerRef);
void (*_Export_ArkUIViewController_keyboardWillShow)(void* controllerRef, libkn_KFloat keyboardHeight);
libkn_KBoolean (*_Export_ArkUIViewController_onBackPress)(void* controllerRef);
void (*_Export_ArkUIViewController_onFinalize)(void* controllerRef);
void (*_Export_ArkUIViewController_onFocusEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_onFrame)(void* controllerRef, libkn_KLong timestamp, libkn_KLong targetTimestamp);
void (*_Export_ArkUIViewController_onKeyEvent)(void* controllerRef);
void (*_Export_ArkUIViewController_onPageHide)(void* controllerRef);
void (*_Export_ArkUIViewController_onPageShow)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceChanged)(void* controllerRef, libkn_KInt width, libkn_KInt height);
void (*_Export_ArkUIViewController_onSurfaceCreated)(void* controllerRef, void* xcomponentPtr, libkn_KInt width, libkn_KInt height);
void (*_Export_ArkUIViewController_onSurfaceDestroyed)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceHide)(void* controllerRef);
void (*_Export_ArkUIViewController_onSurfaceShow)(void* controllerRef);
libkn_KInt (*_Export_ArkUIViewController_requestSyncRefresh)(void* controllerRef);
const char* (*_Export_ArkUIViewController_sendMessage)(void* controllerRef, const char* type, const char* message);
void (*_Export_ArkUIViewController_setContext)(void* controllerRef, void* context);
void (*_Export_ArkUIViewController_setEnv)(void* controllerRef, void* env);
void (*_Export_ArkUIViewController_setId)(void* controllerRef, const char* id);
void (*_Export_ArkUIViewController_setMessenger)(void* controllerRef, void* messenger);
void (*_Export_ArkUIViewController_setRootView)(void* controllerRef, void* backRootView, void* foreRootView, void* touchableRootView);
void (*_Export_ArkUIViewController_setUIContext)(void* controllerRef, void* uiContext);
void (*_Export_ArkUIViewController_setXComponentRender)(void* controllerRef, void* render);
void (*_Export_ArkUIViewInitializer_init)(void* env, void* exports);
} arkui;
} ui;
} export_;
} compose;
} androidx;
struct {
struct {
struct {
struct {
libkn_KInt (*test1_composeapp_generated_resources_Res_array$stableprop_getter)();
libkn_KInt (*test1_composeapp_generated_resources_Res_drawable$stableprop_getter)();
libkn_KInt (*test1_composeapp_generated_resources_Res_font$stableprop_getter)();
libkn_KInt (*test1_composeapp_generated_resources_Res_plurals$stableprop_getter)();
libkn_KInt (*test1_composeapp_generated_resources_Res_string$stableprop_getter)();
libkn_KInt (*test1_composeapp_generated_resources_Res_array$stableprop_getter_)();
libkn_KInt (*test1_composeapp_generated_resources_Res_drawable$stableprop_getter_)();
libkn_KInt (*test1_composeapp_generated_resources_Res_font$stableprop_getter_)();
libkn_KInt (*test1_composeapp_generated_resources_Res_plurals$stableprop_getter_)();
libkn_KInt (*test1_composeapp_generated_resources_Res_string$stableprop_getter_)();
libkn_KInt (*test1_composeapp_generated_resources_Res_array$stableprop_getter__)();
libkn_KInt (*test1_composeapp_generated_resources_Res_drawable$stableprop_getter__)();
libkn_KInt (*test1_composeapp_generated_resources_Res_font$stableprop_getter__)();
libkn_KInt (*test1_composeapp_generated_resources_Res_plurals$stableprop_getter__)();
libkn_KInt (*test1_composeapp_generated_resources_Res_string$stableprop_getter__)();
libkn_KInt (*test1_composeapp_generated_resources_Res_array$stableprop_getter___)();
libkn_KInt (*test1_composeapp_generated_resources_Res_drawable$stableprop_getter___)();
libkn_KInt (*test1_composeapp_generated_resources_Res_font$stableprop_getter___)();
libkn_KInt (*test1_composeapp_generated_resources_Res_plurals$stableprop_getter___)();
libkn_KInt (*test1_composeapp_generated_resources_Res_string$stableprop_getter___)();
} resources;
} generated;
} composeapp;
} test1;
} root;
} kotlin;
} libkn_ExportedSymbols;
extern libkn_ExportedSymbols* libkn_symbols(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* KONAN_LIBKN_H */
#include "libkn_api.h"
#include "napi/native_api.h"
#include <rawfile/raw_file_manager.h>
#include <dlfcn.h>
static napi_value MainArkUIViewController(napi_env env, napi_callback_info info) {
return reinterpret_cast<napi_value>(MainArkUIViewController(env));
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
androidx_compose_ui_arkui_init(env, exports);
napi_property_descriptor desc[] = {
{"MainArkUIViewController", nullptr, MainArkUIViewController, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void*)0),
.reserved = { 0 },
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
napi_module_register(&demoModule);
}
import { ArkUIViewController } from "compose/src/main/cpp/types/libcompose_arkui_utils";
export const MainArkUIViewController: () => ArkUIViewController
{
"name": "libentry.so",
"types": "./Index.d.ts",
"version": "1.0.0",
"description": "Please describe the basic information."
}
......@@ -45,4 +45,4 @@ export default class EntryAbility extends UIAbility {
// Ability has back to background
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
}
}
\ No newline at end of file
}
......@@ -13,4 +13,4 @@ export default class EntryBackupAbility extends BackupExtensionAbility {
hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
await Promise.resolve();
}
}
\ No newline at end of file
}
import { promptAction } from '@kit.ArkUI';
interface ButtonArgs {
text: string
backgroundColor: string
}
@Builder
export function buttonBuilder(args: ButtonArgs) {
button()
}
@Component
export struct button {
@Consume compose_args: ButtonArgs
build() {
Column() {
Button(this.compose_args.text).backgroundColor(this.compose_args.backgroundColor).width('100%').onClick(e => {
console.log(`Button Clicked: ${this.compose_args.text}`)
}).height('70%')
Stack().height('10%')
}
}
}
interface TextArgs {
id: string
text: string
backgroundColor: string
}
@Builder
export function textBuilder(args: TextArgs) {
text()
}
@Component
export struct text {
@Consume compose_args: TextArgs
build() {
Text(this.compose_args.id + " " + this.compose_args.text)
.backgroundColor(this.compose_args.backgroundColor)
.width('100%')
.height('100%')
.borderRadius('5vp')
.onClick(e => {
console.log(`Text Clicked: ${JSON.stringify(this.compose_args)}`)
})
}
}
@Builder
export function labelBuilder(args: ButtonArgs) {
label()
}
@Component
export struct label {
@Consume compose_args: ButtonArgs
build() {
Column() {
Button(`+ ${this.compose_args.text}`, { type: ButtonType.Normal })
.backgroundColor(this.compose_args.backgroundColor)
.width('100%')
.height('50%')
.borderRadius(2)
.onClick(e => {
promptAction.showToast({
message: this.compose_args.text
})
})
Text(this.compose_args.text).backgroundColor(Color.Orange).width('100%').height('50%')
}
}
}
@Builder
export function layerBuilder(args: ButtonArgs) {
layer()
}
@Component
export struct layer {
@Consume compose_args: ButtonArgs
build() {
Stack({ alignContent: Alignment.BottomEnd }) {
Text(this.compose_args.text)
}
.width('100%')
.height('100%')
.backgroundColor(this.compose_args.backgroundColor)
.onClick(() => {
promptAction.showToast({ message: `${this.compose_args.text} Clicked` })
})
.onTouch(e => {
console.log(`layer ${this.compose_args.text} onTouch`)
})
}
}
@Builder
export function buttonWrapContentBuilder(args: ButtonArgs) {
buttonWrapContent()
}
@Component
export struct buttonWrapContent {
@Consume compose_args: ButtonArgs
build() {
Column() {
Button(this.compose_args.text).backgroundColor(this.compose_args.backgroundColor).width('100%').onClick(e => {
console.log(`Button Clicked: ${this.compose_args.text}`)
})
Text(this.compose_args.text).backgroundColor(this.compose_args.backgroundColor).width('100%').onClick(e => {
console.log(`Text Clicked: ${this.compose_args.text}`)
})
}
}
}
interface InputArgs {
text: string
}
@Builder
export function textInputBuilder(args: InputArgs) {
textInput()
}
@Component
export struct textInput {
@Consume compose_args: InputArgs
build() {
Column() {
TextInput({ text: $$this.compose_args.text }).onChange(value => {
console.log(`/// onChange: ${value}`)
})
Text("ArkUI组件更新:").fontColor(Color.Gray).margin({ top: 30 })
Text(this.compose_args.text)
.width('100%')
.padding(10)
.border({ width: 1, color: Color.Gray })
}.alignItems(HorizontalAlign.Start)
}
}
@Builder
export function verticalListBuilder(args?: object) {
verticalList()
}
@Component
export struct verticalList {
build() {
Row() {
List() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`)
.fontSize(16)
.fontColor(Color.White)
}
.borderRadius(2)
.height('100vp')
.padding(10)
}.padding(10)
})
}.listDirection(Axis.Vertical).height('100%').width('40%')
Stack().width('20%').height('100%').borderWidth(1)
Scroll() {
Column() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`).fontSize(16).fontColor(Color.White)
}
.borderRadius(2).height('100vp').padding(10)
}.padding(10)
})
}
}.scrollable(ScrollDirection.Vertical).height('100%').width('40%')
}
}
}
@Builder
export function horizontalListBuilder(args?: object) {
horizontalList()
}
@Component
export struct horizontalList {
build() {
Column() {
List() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`).fontSize(16).fontColor(Color.White)
}
.borderRadius(2).height('100vp')
}.padding(10)
})
}.listDirection(Axis.Horizontal).height('40%').width('100%')
Stack().width('100%').height('20%').borderWidth(1)
Scroll() {
Row() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number, index) => {
ListItem() {
Button({ type: ButtonType.Normal }) {
Text(`Ark Button ${index}`).fontSize(16).fontColor(Color.White)
}
.borderRadius(2).height('100vp')
}.padding(10)
})
}
}.scrollable(ScrollDirection.Horizontal).height('40%').width('100%')
}
}
}
import { registerComposeInteropBuilder } from 'compose/src/main/ets/compose/ArkUIView';
import {
buttonBuilder,
textBuilder,
labelBuilder,
textInputBuilder,
buttonWrapContentBuilder,
layerBuilder,
verticalListBuilder,
horizontalListBuilder,
} from './ComposeInterops';
export function registerComposeInteropBuilders() {
registerComposeInteropBuilder('button', buttonBuilder)
registerComposeInteropBuilder('label', labelBuilder)
registerComposeInteropBuilder('buttonWrapContent', buttonWrapContentBuilder)
registerComposeInteropBuilder('textInput', textInputBuilder)
registerComposeInteropBuilder('layer', layerBuilder)
registerComposeInteropBuilder('text', textBuilder)
registerComposeInteropBuilder('verticalList', verticalListBuilder)
registerComposeInteropBuilder('horizontalList', horizontalListBuilder)
}
import { ArkUIViewController, Compose } from 'compose';
import { hilog } from '@kit.PerformanceAnalysisKit';
import nativeApi from 'libentry.so';
import { registerComposeInteropBuilders } from './ComposeSample';
registerComposeInteropBuilders();
const DOMAIN = 0x0000;
@Entry
@Component
struct Index {
private controller: ArkUIViewController | undefined = undefined;
@State errorMessage: string = 'Native module not ready';
aboutToAppear() {
if (nativeApi === undefined) {
hilog.error(DOMAIN, 'Compose', 'nativeApi is undefined, cannot create controller');
this.errorMessage = 'nativeApi is undefined';
return;
}
try {
this.controller = nativeApi.MainArkUIViewController();
const state = this.controller ? 'created' : 'not_created';
hilog.info(DOMAIN, 'Compose', 'controller init state: %{public}s', state);
if (!this.controller) {
this.errorMessage = 'Controller creation failed (returned null)';
}
} catch (e) {
hilog.error(DOMAIN, 'Compose', 'Exception creating controller: %{public}s', JSON.stringify(e));
this.errorMessage = 'Exception creating controller: ' + JSON.stringify(e);
}
}
build() {
Column() {
if (this.controller) {
Compose({
controller: this.controller,
libraryName: 'entry',
onBackPressed: () => this.controller!.onBackPress()
})
} else {
Text(this.errorMessage)
}
}
.width('100%')
.height('100%')
}
onPageHide() {
if (this.controller) {
this.controller.onPageHide();
}
}
onBackPressed(): boolean {
return this.controller ? this.controller.onBackPress() : false;
}
}
......@@ -20,6 +20,7 @@
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"orientation": "auto_rotation",
"skills": [
{
"entities": [
......@@ -47,4 +48,4 @@
}
]
}
}
\ No newline at end of file
}
......@@ -4,4 +4,4 @@
"background" : "$media:background",
"foreground" : "$media:foreground"
}
}
\ No newline at end of file
}
const NativeMock: Record<string, Object> = {
'add': (a: number, b: number) => {
return a + b;
},
};
export default NativeMock;
{
"libentry.so": {
"source": "src/mock/Libentry.mock.ets"
}
}
......@@ -32,4 +32,4 @@ export default function abilityTest() {
expect(a).assertEqual(a);
})
})
}
\ No newline at end of file
}
......@@ -2,4 +2,4 @@ import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}
\ No newline at end of file
}
......@@ -2,4 +2,4 @@ import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}
\ No newline at end of file
}
......@@ -30,4 +30,4 @@ export default function localUnitTest() {
expect(a).assertEqual(a);
});
});
}
\ No newline at end of file
}
......@@ -3,4 +3,4 @@ import { appTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
}
\ No newline at end of file
}
rootProject.name = "Test1"
// 启用类型安全项目访问器特性(Type-safe project accessors)
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
/**
专门管理 Gradle 插件的解析和应用:
影响 plugins {} 块中的插件解析
影响 buildscript {} 块中的插件解析
影响插件版本管理
影响插件仓库配置
只在构建脚本配置阶段生效
*/
pluginManagement {
repositories {
maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")
// 引入 Gradle 插件门户(主要用于查找 Gradle 插件)
gradlePluginPortal()
}
}
/**
专门管理项目依赖的解析:
影响 dependencies {} 块中的依赖解析
影响 implementation、api、compileOnly 等依赖声明
影响依赖版本管理
影响依赖仓库配置
在整个项目构建过程中生效
*/
dependencyResolutionManagement {
repositories {
maven("https://maven.eazytec-cloud.com/nexus/repository/maven-public/")
}
}
// 包含 composeApp 模块
include(":composeApp")
// 测试异常格式日志功能
class TestAbnormalLogGenerator {
static DOMAIN_APP = 0x0001;
static TAG_APP = 'BigLogApp';
static info(domain, tag, format, ...args) {
console.log(`[INFO] [Domain:${domain}] [${tag}] ${format}`, ...args);
}
static error(domain, tag, format, ...args) {
console.log(`[ERROR] [Domain:${domain}] [${tag}] ${format}`, ...args);
}
// 模拟异常格式日志生成
static generateAbnormalFormatLogs() {
console.log('\n=== 开始测试异常格式日志 ===');
// 1. 参数数量不匹配
console.log('--- 测试1: 参数数量不匹配 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'用户%{public}s执行%{public}s操作成功', '张三');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式1异常捕获: %{public}s', e.message);
}
// 2. 参数类型不匹配
console.log('--- 测试2: 参数类型不匹配 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'HTTP请求状态码:%{public}d', 'not_a_number');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式2异常捕获: %{public}s', e.message);
}
// 3. 缺少格式占位符
console.log('--- 测试3: 缺少格式占位符 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'数据库操作完成', '额外参数会被忽略');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式3异常捕获: %{public}s', e.message);
}
// 4. 格式字符串为空
console.log('--- 测试4: 格式字符串为空 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'', '参数1', '参数2');
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式4异常捕获: %{public}s', e.message);
}
// 5. 复杂嵌套格式错误
console.log('--- 测试5: 复杂嵌套格式错误 ---');
try {
this.info(this.DOMAIN_APP, this.TAG_APP,
'系统资源使用 内存:%{public}d%% CPU:%{public}d%% 磁盘:%{public}d%%',
75, 'invalid_cpu', 90);
} catch (e) {
this.error(this.DOMAIN_APP, this.TAG_APP,
'格式5异常捕获: %{public}s', e.message);
}
console.log('=== 异常格式日志测试完成 ===\n');
}
// 模拟边界条件日志生成
static generateBoundaryLogs() {
console.log('\n=== 开始测试边界条件日志 ===');
// 1. 超长字符串
const longString = 'A'.repeat(10000);
console.log('--- 测试1: 超长字符串 ---');
this.info(this.DOMAIN_APP, this.TAG_APP,
'超长日志内容长度:%{public}d 字符串预览:%{public}s',
longString.length, longString.substring(0, 100));
// 2. 极端数值
console.log('--- 测试2: 极端数值 ---');
this.info(this.DOMAIN_APP, this.TAG_APP,
'极端数值测试 负数:%{public}d 零:%{public}d 超大数:%{public}d',
-999999, 0, 999999999);
// 3. 特殊字符
console.log('--- 测试3: 特殊字符 ---');
const specialChars = '特殊字符测试: !@#$%^&*()_+-=[]{}|;:,.<>?中文测试';
this.info(this.DOMAIN_APP, this.TAG_APP,
'特殊字符日志:%{public}s', specialChars);
// 4. 空值和undefined
console.log('--- 测试4: 空值和undefined ---');
this.info(this.DOMAIN_APP, this.TAG_APP,
'空值测试 null:%{public}s undefined:%{public}s', null, undefined);
console.log('=== 边界条件日志测试完成 ===\n');
}
}
// 运行测试
console.log('开始测试异常格式日志功能...\n');
TestAbnormalLogGenerator.generateAbnormalFormatLogs();
TestAbnormalLogGenerator.generateBoundaryLogs();
console.log('所有测试完成!');
\ No newline at end of file
// 模拟测试日志生成器的核心逻辑
// 这个脚本用于验证我们创建的日志生成功能
class MockHilog {
static debug(domain, tag, format, ...args) {
console.log(`[DEBUG] [Domain:${domain}] [${tag}] ${this.formatMessage(format, args)}`);
}
static info(domain, tag, format, ...args) {
console.log(`[INFO] [Domain:${domain}] [${tag}] ${this.formatMessage(format, args)}`);
}
static warn(domain, tag, format, ...args) {
console.log(`[WARN] [Domain:${domain}] [${tag}] ${this.formatMessage(format, args)}`);
}
static error(domain, tag, format, ...args) {
console.log(`[ERROR] [Domain:${domain}] [${tag}] ${this.formatMessage(format, args)}`);
}
static fatal(domain, tag, format, ...args) {
console.log(`[FATAL] [Domain:${domain}] [${tag}] ${this.formatMessage(format, args)}`);
}
static formatMessage(format, args) {
let message = format;
args.forEach((arg, index) => {
const placeholder = `%{public}s`;
message = message.replace(placeholder, arg);
});
return message;
}
}
class MockLogManager {
static DOMAIN_APP = 0x0001;
static DOMAIN_NETWORK = 0x0002;
static DOMAIN_DATABASE = 0x0003;
static DOMAIN_FILE = 0x0004;
static DOMAIN_UI = 0x0005;
static DOMAIN_SYSTEM = 0x0006;
static TAG_APP = 'BigLogApp';
static TAG_NETWORK = 'NetworkService';
static TAG_DATABASE = 'DatabaseOps';
static TAG_FILE = 'FileHandler';
static TAG_UI = 'UIComponent';
static TAG_SYSTEM = 'SystemService';
static debug(domain, tag, format, ...args) {
MockHilog.debug(domain, tag, format, ...args);
}
static info(domain, tag, format, ...args) {
MockHilog.info(domain, tag, format, ...args);
}
static warn(domain, tag, format, ...args) {
MockHilog.warn(domain, tag, format, ...args);
}
static error(domain, tag, format, ...args) {
MockHilog.error(domain, tag, format, ...args);
}
static fatal(domain, tag, format, ...args) {
MockHilog.fatal(domain, tag, format, ...args);
}
static batchLog(level, domain, tag, format, count, ...args) {
for (let i = 0; i < count; i++) {
const timestamp = Date.now();
const message = `${format} [Batch:${i+1}/${count}] [Time:${timestamp}]`;
switch (level) {
case 'debug':
this.debug(domain, tag, message, ...args);
break;
case 'info':
this.info(domain, tag, message, ...args);
break;
case 'warn':
this.warn(domain, tag, message, ...args);
break;
case 'error':
this.error(domain, tag, message, ...args);
break;
case 'fatal':
this.fatal(domain, tag, message, ...args);
break;
}
}
}
}
class MockLogGenerator {
constructor() {
this.isGenerating = false;
this.intervalId = null;
}
static USERS = ['张三', '李四', '王五', '赵六', '钱七'];
static ACTIONS = ['登录', '登出', '查询', '更新', '删除', '创建'];
static STATUS_CODES = [200, 404, 500, 403, 401];
static FILE_NAMES = ['config.json', 'data.txt', 'image.png', 'document.pdf', 'log.log'];
static DB_OPERATIONS = ['SELECT', 'INSERT', 'UPDATE', 'DELETE'];
startContinuousLogging(interval = 1000) {
if (this.isGenerating) {
MockLogManager.warn(MockLogManager.DOMAIN_APP, MockLogManager.TAG_APP, '日志生成已在运行中');
return;
}
this.isGenerating = true;
MockLogManager.info(MockLogManager.DOMAIN_APP, MockLogManager.TAG_APP, '开始持续生成日志,间隔: %{public}d ms', interval);
this.intervalId = setInterval(() => {
this.generateRandomLogs();
}, interval);
}
stopContinuousLogging() {
if (!this.isGenerating) {
MockLogManager.warn(MockLogManager.DOMAIN_APP, MockLogManager.TAG_APP, '日志生成未在运行');
return;
}
this.isGenerating = false;
if (this.intervalId !== null) {
clearInterval(this.intervalId);
this.intervalId = null;
}
MockLogManager.info(MockLogManager.DOMAIN_APP, MockLogManager.TAG_APP, '停止持续生成日志');
}
generateRandomLogs() {
const logTypes = [
() => this.generateAppLogs(),
() => this.generateNetworkLogs(),
() => this.generateDatabaseLogs(),
() => this.generateFileLogs(),
() => this.generateSystemLogs()
];
const count = Math.floor(Math.random() * 3) + 1;
const selectedTypes = this.shuffleArray(logTypes).slice(0, count);
selectedTypes.forEach(generateFunc => {
generateFunc();
});
}
generateAppLogs() {
const user = this.getRandomItem(MockLogGenerator.USERS);
const action = this.getRandomItem(MockLogGenerator.ACTIONS);
const success = Math.random() > 0.2;
if (success) {
MockLogManager.info(MockLogManager.DOMAIN_APP, MockLogManager.TAG_APP,
'用户%{public}s执行%{public}s操作成功', user, action);
} else {
MockLogManager.error(MockLogManager.DOMAIN_APP, MockLogManager.TAG_APP,
'用户%{public}s执行%{public}s操作失败', user, action);
}
}
generateNetworkLogs() {
const statusCode = this.getRandomItem(MockLogGenerator.STATUS_CODES);
const url = `https://api.example.com/data/${Math.floor(Math.random() * 1000)}`;
if (statusCode === 200) {
MockLogManager.info(MockLogManager.DOMAIN_NETWORK, MockLogManager.TAG_NETWORK,
'HTTP请求成功 URL:%{public}s Status:%{public}d', url, statusCode);
} else {
MockLogManager.error(MockLogManager.DOMAIN_NETWORK, MockLogManager.TAG_NETWORK,
'HTTP请求失败 URL:%{public}s Status:%{public}d', url, statusCode);
}
}
generateDatabaseLogs() {
const operation = this.getRandomItem(MockLogGenerator.DB_OPERATIONS);
const tableName = `table_${Math.floor(Math.random() * 10)}`;
const recordCount = Math.floor(Math.random() * 100) + 1;
const duration = Math.floor(Math.random() * 500) + 10;
MockLogManager.info(MockLogManager.DOMAIN_DATABASE, MockLogManager.TAG_DATABASE,
'数据库操作 %{public}s %{public}s 影响记录数:%{public}d 耗时:%{public}dms',
operation, tableName, recordCount, duration);
}
generateFileLogs() {
const fileName = this.getRandomItem(MockLogGenerator.FILE_NAMES);
const operation = Math.random() > 0.5 ? '读取' : '写入';
const fileSize = Math.floor(Math.random() * 10240) + 1024;
const success = Math.random() > 0.1;
if (success) {
MockLogManager.info(MockLogManager.DOMAIN_FILE, MockLogManager.TAG_FILE,
'文件%{public}s操作成功 文件名:%{public}s 大小:%{public}d bytes',
operation, fileName, fileSize);
} else {
MockLogManager.error(MockLogManager.DOMAIN_FILE, MockLogManager.TAG_FILE,
'文件%{public}s操作失败 文件名:%{public}s', operation, fileName);
}
}
generateSystemLogs() {
const memoryUsage = Math.floor(Math.random() * 80) + 10;
const cpuUsage = Math.floor(Math.random() * 90) + 5;
const batteryLevel = Math.floor(Math.random() * 100);
MockLogManager.info(MockLogManager.DOMAIN_SYSTEM, MockLogManager.TAG_SYSTEM,
'系统状态监控 内存使用率:%{public}d%% CPU使用率:%{public}d%% 电池电量:%{public}d%%',
memoryUsage, cpuUsage, batteryLevel);
if (memoryUsage > 80) {
MockLogManager.warn(MockLogManager.DOMAIN_SYSTEM, MockLogManager.TAG_SYSTEM,
'内存使用率过高:%{public}d%%,建议清理缓存', memoryUsage);
}
if (batteryLevel < 20) {
MockLogManager.warn(MockLogManager.DOMAIN_SYSTEM, MockLogManager.TAG_SYSTEM,
'电池电量低:%{public}d%%,请及时充电', batteryLevel);
}
}
generateBatchLogs(count, level = 'info') {
MockLogManager.batchLog(level, MockLogManager.DOMAIN_APP, MockLogManager.TAG_APP,
'批量日志生成 测试消息', count);
}
getRandomItem(array) {
return array[Math.floor(Math.random() * array.length)];
}
shuffleArray(array) {
const newArray = [...array];
for (let i = newArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[newArray[i], newArray[j]] = [newArray[j], newArray[i]];
}
return newArray;
}
isRunning() {
return this.isGenerating;
}
}
// 测试函数
function runTests() {
console.log('=== 开始测试日志生成器 ===\n');
const generator = new MockLogGenerator();
// 测试1: 单次生成各种类型日志
console.log('--- 测试1: 单次生成各种类型日志 ---');
generator.generateAppLogs();
generator.generateNetworkLogs();
generator.generateDatabaseLogs();
generator.generateFileLogs();
generator.generateSystemLogs();
console.log('\n--- 测试2: 批量生成日志 ---');
generator.generateBatchLogs(5, 'info');
console.log('\n--- 测试3: 错误级别日志 ---');
generator.generateBatchLogs(3, 'error');
console.log('\n--- 测试4: 启动持续生成 ---');
generator.startContinuousLogging(500); // 500ms间隔
// 运行5秒后停止
setTimeout(() => {
console.log('\n--- 测试5: 停止持续生成 ---');
generator.stopContinuousLogging();
console.log('\n=== 测试完成 ===');
}, 5000);
}
// 运行测试
runTests();
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment