uniapp APP端 日誌寫入 查看 分享
本來我是想,借用 Android 原生什麼框架的,持久化寫入本地 .txt 啥的, 找了一圈發現用起來挺麻煩的, 而且效果也不好;
於是自己着手 就寫個了;(內部應用)
大致效果日下:
- 日誌安每天 進行文件存儲 最多顯示九天的
- 每個日誌可以 瀏覽內容
- 還可以調用 系統級 分享出去,方便開發時候 找尋錯誤
大致步驟如下:
- Java 原生實現一個 可以按照日期 寫入文件的類
- Java 封裝給 uniapp 這邊調用,
- Java 封裝一個接口 返回文件夾路徑,給 uniapp 加載顯示 文件使用
LogerUtils.java
package com.uniapp.runscore.Util;
import android.util.Log;
import com.uniapp.runscore.SetupHookProxy;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LogerUtils {
//獲取日誌文件路徑
public static String getRoot() {
return SetupHookProxy.application.getExternalFilesDir("").getAbsolutePath()+"/Logs/";
}
public static String GetFileFullPath() throws IOException {
File dir = new File(getRoot());
if(!dir.exists()){
dir.mkdir();
}
Date date = new Date();
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
String fileName = "Log_"+format.format(date)+".txt";
File file = new File(getRoot()+fileName);
if( !file.exists()){
file.createNewFile();
}
return file.getPath();
}
//寫入日誌
public static void Line(String content) {
Log.i("setup",content);
try {
String filePath = GetFileFullPath();
FileWriter fw = new FileWriter(filePath, true);
Date date = new Date();
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String message = "-->"+format.format(date)+": "+content;
fw.write(message);
fw.write(System.getProperty("line.separator"));//寫入換行
fw.close();
} catch (IOException e) {
e.printStackTrace();
Log.i("setup","LogerWrite 日誌文件:"+e.getMessage());
}
}
public static File[] reverseArray( File[] Array) {
File[] new_array = new File[Array.length];
for (int i = 0; i < Array.length; i++) {
// 反轉後數組的第一個元素等於源數組的最後一個元素:
new_array[i] = Array[Array.length - i - 1];
}
return new_array;
}
}
SetupEnvironment.java 是繼承 WXSDKEngine.DestroyableModule Uniapp 原生插件的寫法
下面代碼就是 提供給 uniapp 調用的
@JSMethod(uiThread = true) public void LogUtils(JSONObject options){ if( options.containsKey("message")){ LogerUtils.Line("---Uniapp---:> "+options.getString("message")); } }
package com.uniapp.runscore;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.StrictMode;
import android.text.TextUtils;
import com.alibaba.fastjson.JSONObject;
import com.taobao.weex.WXSDKEngine;
import com.taobao.weex.annotation.JSMethod;
import com.taobao.weex.bridge.JSCallback;
import com.uniapp.runscore.NotificationService.NLService;
import com.uniapp.runscore.Util.LogerUtils;
import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
public class SetupEnvironment extends WXSDKEngine.DestroyableModule {
public static Context mContext;
public static String noticeUrl = null;
public static String noticeAuthorization = null;
public static JSCallback PaymentCallback = null;
@JSMethod(uiThread = true)
public void Init( JSONObject options){
this.mContext = this.mWXSDKInstance.getContext();
this.noticeUrl = options.getString("noticeUrl");
this.noticeAuthorization = options.getString("Authorization");
// Log.i("setup"," this.noticeUrl:"+this.noticeUrl);
// Log.i("setup"," this.noticeUrl:"+this.noticeAuthorization);
LogerUtils.Line("this.noticeUrl:"+this.noticeUrl);
LogerUtils.Line("this.noticeAuthorization:"+this.noticeAuthorization);
LogerUtils.Line("SetupEnvironment Init");
}
@JSMethod(uiThread = true)
public void LogUtils(JSONObject options){
if( options.containsKey("message")){
LogerUtils.Line("---Uniapp---:> "+options.getString("message"));
}
}
@JSMethod(uiThread = true)
public void GetLogDir(JSCallback jsCallback){
JSONObject result = new JSONObject();
result.put("path", LogerUtils.getRoot());
jsCallback.invoke(result);
}
//獲取日誌 絕對路徑
@JSMethod(uiThread = true)
public void GetArrayLogs(JSCallback jsCallback){
List<String> list = new ArrayList<String>();
File[] files = new File(LogerUtils.getRoot()).listFiles();
files = LogerUtils.reverseArray(files);//反轉
// for (File file : files) {//遍歷File數組
// if(file.isFile()&&file.getName().endsWith(".txt")) {//判斷對象是否是以.txt 結尾的類型的文件,是的話就輸出
// list.add(file.getPath());
// }
// }
for(int i = 0; i < (files.length < 10 ? files.length:9); i ++){
if(files[i].isFile()&&files[i].getName().endsWith(".txt")) {//判斷對象是否是以.txt 結尾的類型的文件,是的話就輸出
list.add(files[i].getPath());
}
}
JSONObject result = new JSONObject();
result.put("path", list.toArray(new String[]{}));
jsCallback.invoke(result);
}
//分享日誌
@JSMethod(uiThread = true)
public void onSharelog(JSONObject options){
if(!options.containsKey("filePath") ){
return;
}
String filePath = options.getString("filePath");
if (TextUtils.isEmpty(filePath)) {
return;
}
File file = new File(filePath);
checkFileUriExposure();
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
//intent.setType("*/*"); //分享文件類型
intent.setType("text/plain");
this.mWXSDKInstance.getContext().startActivity(Intent.createChooser(intent, "分享"));
}
private void checkFileUriExposure() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
}
}
//返回電量
@JSMethod(uiThread = true)
public void onGetBattery(JSCallback jsCallback){
if( NLService.getNlService() != null){
float battery = NLService.getNlService().getBattery();
JSONObject result = new JSONObject();
result.put("battery", battery);
jsCallback.invoke(result);
}
}
@JSMethod(uiThread = true)
public void Environment(JSCallback jsCallback){
// this.jsCallback = jsCallback;
}
@JSMethod(uiThread = true)
public void OnPayment(JSCallback jsCallback){
this.mContext = this.mWXSDKInstance.getContext();
this.PaymentCallback = jsCallback;
}
//把應用的NotificationListenerService實現類disable再enable,即可觸發系統rebind操作
private void toggleNotificationListenerService() {
PackageManager pm = this.mWXSDKInstance.getContext().getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName(this.mWXSDKInstance.getContext(), NLService.class),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(
new ComponentName(this.mWXSDKInstance.getContext(), NLService.class),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
@Override
public void destroy() {
}
}
現在我們已經可以從 java 代碼中獲取,日誌文件 .txt 文件的路徑,然後交給 Uniapp 調用 讀取就可以了;
在這裏 uniapp 讀取文件 有個分別;
- 讀取 返回 Base64 編碼
plus.io.resolveLocalFileSystemURL(path, function(entry) { entry.file(function(file) { var fileReader = new plus.io.FileReader(); //alert("getFile:" + JSON.stringify(file)); fileReader.readAsDataURL(file); fileReader.onloadend = function(evt) { // console.log(JSON.stringify(evt.target.result)); ////base64字符串 callback(evt.target.result); } }) });
- 讀取 返回 文本編碼
plus.io.resolveLocalFileSystemURL( function(entry) { entry.file( function(file) { var fileReader = new plus.io.FileReader(); fileReader.readAsText(file, 'utf-8'); fileReader.onloadend = function(evt) { if (callback) { //返回 文本 編碼內容 callback(evt.target.result); } }.bind(this); }.bind(this) ); }.bind(this) );
最後我們就用 <pre> 標籤原樣顯示了
<template> <view class="showlogs"> <view class="top"> <view class="top-back" @tap="onBack()"></view> <view class="top-title">{{ datum.name }}</view> <view class="top-share" @tap="onShare()">發送</view> </view> <view class="mid-area"> <pre>{{result}}</pre> </view> </view> </template> <script> export default { data() { return { datum: { name: '', path: '' }, result: '' }; }, onLoad(e) { if (e) { this.datum = JSON.parse(decodeURIComponent(e.datum)); this.resoultLogs(msg => { this.result = msg; // console.log("this.result:",this.result.length) }); } }, methods: { resoultLogs(callback) { plus.io.resolveLocalFileSystemURL( this.datum.path, function(entry) { entry.file( function(file) { var fileReader = new plus.io.FileReader(); fileReader.readAsText(file, 'utf-8'); fileReader.onloadend = function(evt) { if (callback) { callback(evt.target.result); } }.bind(this); }.bind(this) ); }.bind(this) ); }, onShare() { const SetupEnvironment = uni.requireNativePlugin('SetupEnvironment'); SetupEnvironment.onSharelog({ filePath: this.datum.path }); }, onBack() { uni.navigateBack(); } }, computed: { getlogs() { let logs = ''; this.resoultLogs(meaage => { logs = meaage; }); return logs; } } }; </script> <style lang="scss" scoped> .showlogs { position: absolute; width: 100%; height: 100%; top: 0; buttom: 0; .top { position: relative; height: 176rpx; width: 100%; background: #000000; .top-back { position: absolute; left: 40rpx; top: 110rpx; width: 46rpx; height: 76rpx; background: url('../../static/images/common/[email protected]') no-repeat; background-size: 30%; } .top-title { position: absolute; width: 50%; text-align: center; left: 0; right: 0; margin: auto; top: 104rpx; font-weight: bold; color: #ffffff; font-size: 31rpx; // background: #f0ad4e; } .top-share { width: 20%; text-align: right; position: absolute; top: 104rpx; right: 43rpx; font-weight: bold; color: #ffffff; font-size: 31rpx; } } .mid-area { position: absolute; top: 176rpx; bottom: 0px; width: 100%; overflow-y: auto; font-size: 22rpx; color: #000000; background: #5797ff; } } </style>