uniapp APP端 日誌寫入 查看 分享

                                           uniapp APP端  日誌寫入  查看  分享                         


本來我是想,借用 Android 原生什麼框架的,持久化寫入本地 .txt 啥的, 找了一圈發現用起來挺麻煩的, 而且效果也不好;

於是自己着手 就寫個了;(內部應用

大致效果日下:

  • 日誌安每天 進行文件存儲 最多顯示九天的
  • 每個日誌可以 瀏覽內容
  • 還可以調用 系統級 分享出去,方便開發時候 找尋錯誤

大致步驟如下:

  1. Java 原生實現一個 可以按照日期 寫入文件的類  
  2. Java 封裝給 uniapp 這邊調用,
  3. 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>

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章