日志
This commit is contained in:
4
uni_modules/yk-log/changelog.md
Normal file
4
uni_modules/yk-log/changelog.md
Normal file
@@ -0,0 +1,4 @@
|
||||
## 1.0.1(2024-10-30)
|
||||
1. 解决中文乱码问题
|
||||
## 1.0.0(2024-10-28)
|
||||
1. 实现日志写入/storage/emulated/0/Android/data/包名/files/Logs中
|
||||
87
uni_modules/yk-log/package.json
Normal file
87
uni_modules/yk-log/package.json
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"id": "yk-log",
|
||||
"displayName": "yk-log 基于uts实现的安卓日志插件",
|
||||
"version": "1.0.1",
|
||||
"description": "基于uts实现的日志插件,保存日志文件到外部存储的私有目录下,目前Android 10及以下测试可用,10以上未测试",
|
||||
"keywords": [
|
||||
"yk-log",
|
||||
"uts",
|
||||
"日志",
|
||||
"Android"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.91"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "uts",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": "2466286500"
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-android": {
|
||||
"minVersion": "21"
|
||||
},
|
||||
"app-ios": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "n",
|
||||
"Android Browser": "n",
|
||||
"微信浏览器(Android)": "n",
|
||||
"QQ浏览器(Android)": "n"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "n",
|
||||
"IE": "n",
|
||||
"Edge": "n",
|
||||
"Firefox": "n",
|
||||
"Safari": "n"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "n",
|
||||
"阿里": "n",
|
||||
"百度": "n",
|
||||
"字节跳动": "n",
|
||||
"QQ": "n",
|
||||
"钉钉": "n",
|
||||
"快手": "n",
|
||||
"飞书": "n",
|
||||
"京东": "n"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
uni_modules/yk-log/readme.md
Normal file
31
uni_modules/yk-log/readme.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# yk-log
|
||||
目前官方的`TextEncoder`提示不支持,自己写的字符转byteArray方法后面会导致生成的字节数组末尾出现额外的零字节(0),所以日志换行之后会有乱码。
|
||||
|
||||
由于手机坏了只有备用机,目前测试Android 10及以下的版本可以,10以上理论上也可以。
|
||||
|
||||
日志文件存储在 /storage/emulated/0/Android/data/包名/files/Logs 目录中
|
||||
|
||||
### 方法
|
||||
|
||||
| 方法名 | 说明 | 参数 |
|
||||
| ------ | -------------------------------------------- | ---- |
|
||||
| write | 写入日志,yyyy-MM-dd HH:mm:ss.SSS-[传入消息] | text |
|
||||
|
||||
### 使用示例
|
||||
|
||||
```js
|
||||
import { write } from '../../uni_modules/yk-log'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
wirteLog() {
|
||||
write("1111")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3
uni_modules/yk-log/utssdk/app-android/config.json
Normal file
3
uni_modules/yk-log/utssdk/app-android/config.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"minSdkVersion": "21"
|
||||
}
|
||||
54
uni_modules/yk-log/utssdk/app-android/index.uts
Normal file
54
uni_modules/yk-log/utssdk/app-android/index.uts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { WriteApi } from '../interface';
|
||||
import SimpleDateFormat from 'java.text.SimpleDateFormat';
|
||||
import Locale from 'java.util.Locale';
|
||||
import FileOutputStream from 'java.io.FileOutputStream';
|
||||
import File from 'java.io.File';
|
||||
import Date from "java.util.Date";
|
||||
import OutputStreamWriter from 'java.io.OutputStreamWriter';
|
||||
|
||||
const LOG_DISPLAY_NAME = "app_log.txt";
|
||||
|
||||
// 字符串转Uint8Array
|
||||
function stringToUint8Array(str: string) : ByteArray{
|
||||
const arr: ByteArray = new ByteArray(str.length);
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
arr.set(i.toInt(), str.charCodeAt(i)!!.toByte());
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// 创建消息格式
|
||||
function createMessage(logMessage : string) : string {
|
||||
const timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()).format(new Date());
|
||||
const logEntry = timestamp + " - " + logMessage + "\n";
|
||||
return logEntry
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
export const write : WriteApi = (logMessage : string) => {
|
||||
const context = UTSAndroid.getAppContext();
|
||||
// 获取应用的私有外部存储目录
|
||||
const externalFilesDir = context!!.getExternalFilesDir(null); // type为null表示根目录
|
||||
if (externalFilesDir == null) {
|
||||
// 外部存储不可用或未挂载
|
||||
return;
|
||||
}
|
||||
|
||||
// 指定放在 应用的私有外部存储目录/Logs 目录中
|
||||
const logDir = new File(externalFilesDir, `Logs`);
|
||||
if (!logDir.exists()) {
|
||||
logDir.mkdirs();
|
||||
}
|
||||
|
||||
const nowDay = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
||||
const fileName = `${nowDay}_${LOG_DISPLAY_NAME}`;
|
||||
const logFile = new File(logDir, fileName);
|
||||
try {
|
||||
const fos = new FileOutputStream(logFile, true)
|
||||
const oStreamWriter = OutputStreamWriter(fos, 'UTF-8')
|
||||
oStreamWriter.append(createMessage(logMessage));
|
||||
oStreamWriter.close()
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
2
uni_modules/yk-log/utssdk/interface.uts
Normal file
2
uni_modules/yk-log/utssdk/interface.uts
Normal file
@@ -0,0 +1,2 @@
|
||||
/* 写入文件 */
|
||||
export type WriteApi = (logMessage : string) => void
|
||||
@@ -1,79 +1,139 @@
|
||||
<template>
|
||||
<view>
|
||||
<web-view :src="url" @onPostMessage="onMessage" @error="onWebViewError"></web-view>
|
||||
<view v-if="loading" class="loading">页面加载中...</view>
|
||||
<view v-if="loadError" class="error">
|
||||
页面加载失败
|
||||
<button @tap="retryLoad">重新加载</button>
|
||||
<web-view v-if="urlAvailable" :src="url"></web-view>
|
||||
<view v-else class="error-container">
|
||||
<text class="error-text">无法访问目标地址,请检查网络连接</text>
|
||||
<button type="primary" @tap="retryConnection">重试</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { write } from '@/uni_modules/yk-log'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
url: '',
|
||||
originalUrl: 'http://192.168.100.201',
|
||||
loading: true,
|
||||
loadError: false
|
||||
url: 'http://192.168.100.201',
|
||||
urlAvailable: false,
|
||||
logMessages: [] // 用于收集日志
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
this.addLog('🏠 home1页面开始加载')
|
||||
console.log('📄 home1 onLoad 执行', options)
|
||||
this.initWebView()
|
||||
},
|
||||
onReady() {
|
||||
this.addLog('✅ home1页面准备就绪')
|
||||
console.log('✅ home1 onReady 执行')
|
||||
},
|
||||
onShow() {
|
||||
this.addLog('👀 home1页面显示')
|
||||
console.log('✅ home1 onShow 执行')
|
||||
},
|
||||
onHide() {
|
||||
this.addLog('🔚 home1页面隐藏')
|
||||
console.log('🔚 home1 onHide 执行')
|
||||
},
|
||||
onUnload() {
|
||||
this.addLog('🗑️ home1页面卸载')
|
||||
console.log('🗑️ home1 onUnload 执行')
|
||||
},
|
||||
onError(err) {
|
||||
this.addLog('💥 home1页面错误: ' + err)
|
||||
console.error('💥 home1页面错误:', err)
|
||||
},
|
||||
methods: {
|
||||
initWebView() {
|
||||
this.loading = true
|
||||
this.loadError = false
|
||||
addLog(message) {
|
||||
const timestamp = new Date().toLocaleTimeString()
|
||||
this.logMessages.push(`[${timestamp}] ${message}`)
|
||||
console.log(message)
|
||||
write(message)
|
||||
},
|
||||
async initWebView() {
|
||||
this.addLog('🌐 开始初始化WebView')
|
||||
this.addLog(`🔗 检查URL可达性: ${this.url}`)
|
||||
|
||||
const timestamp = new Date().getTime()
|
||||
this.url = `${this.originalUrl}?timestamp=${timestamp}`
|
||||
|
||||
// 设置超时检测
|
||||
setTimeout(() => {
|
||||
if (this.loading) {
|
||||
this.loading = false
|
||||
this.loadError = true
|
||||
}
|
||||
}, 10000) // 10秒超时
|
||||
// 检查URL是否可达
|
||||
const isReachable = await this.checkUrlReachability(this.url)
|
||||
|
||||
if (isReachable) {
|
||||
this.urlAvailable = true
|
||||
this.addLog('✅ URL可达,加载WebView')
|
||||
} else {
|
||||
this.urlAvailable = false
|
||||
this.addLog('❌ URL不可达,显示错误页面')
|
||||
}
|
||||
|
||||
// 监听网络状态变化
|
||||
uni.onNetworkStatusChange((res) => {
|
||||
if (res.isConnected && this.loadError) {
|
||||
this.retryLoad()
|
||||
this.addLog(`📶 网络状态变化: ${res.isConnected ? '已连接' : '未连接'}`)
|
||||
if (res.isConnected) {
|
||||
this.retryConnection()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onWebViewError(e) {
|
||||
console.error('WebView加载错误:', e)
|
||||
this.loading = false
|
||||
this.loadError = true
|
||||
// 检查URL可达性
|
||||
checkUrlReachability(url) {
|
||||
return new Promise((resolve) => {
|
||||
// 方法1: 使用uni.request检查
|
||||
uni.request({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
timeout: 5000,
|
||||
success: (res) => {
|
||||
this.addLog(`✅ URL检查成功,状态码: ${res.statusCode}`)
|
||||
resolve(res.statusCode < 400) // 状态码小于400认为可达
|
||||
},
|
||||
fail: (err) => {
|
||||
if (err.errMsg && err.errMsg.includes('request:fail')) {
|
||||
this.addLog('❌ 网络请求失败')
|
||||
resolve(false)
|
||||
} else {
|
||||
// 其他错误(包括CORS)认为URL基本可达
|
||||
this.addLog(`⚠️ URL可能可达,但有CORS限制: ${err.errMsg}`)
|
||||
resolve(true)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onMessage(e) {
|
||||
// WebView内部发送的消息,可以用于确认页面加载完成
|
||||
this.loading = false
|
||||
this.loadError = false
|
||||
},
|
||||
|
||||
retryLoad() {
|
||||
this.initWebView()
|
||||
// 重试连接
|
||||
async retryConnection() {
|
||||
this.addLog('🔄 尝试重新连接')
|
||||
const isReachable = await this.checkUrlReachability(this.url)
|
||||
this.urlAvailable = isReachable
|
||||
|
||||
if (isReachable) {
|
||||
this.addLog('✅ 重新连接成功')
|
||||
uni.showToast({
|
||||
title: '连接成功',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
this.addLog('❌ 重新连接失败')
|
||||
uni.showToast({
|
||||
title: '连接失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
onUnload() {
|
||||
uni.offNetworkStatusChange()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.loading, .error {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
z-index: 9999;
|
||||
<style scoped>
|
||||
.error-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
.error-text {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
color: #999;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
<view class="">
|
||||
<input type="text" class="input" v-model="url">
|
||||
<button type="primary" size="size" @tap="toConfig">跳转</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
url: 'http://192.168.100.201'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toConfig () {
|
||||
let url = '/uni_modules/yykj-tv/pages/home/home' + '?url=' + this.url
|
||||
uni.redirectTo({
|
||||
url: url
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-image: linear-gradient(to bottom, #2E3092, #797979);
|
||||
}
|
||||
.input {
|
||||
width: 50vw;
|
||||
height: 5vh;
|
||||
background-color: #fff;
|
||||
margin-bottom: 2vh;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user