调试日志

日志是调试过程最重要的一环,YukiHookAPI 为开发者封装了一套稳定高效的调试日志功能。

普通日志

你可以调用 YLog.debugYLog.infoYLog.warn 来向控制台打印普通日志。

使用方法如下所示。

示例如下

YLog.debug(msg = "This is a log")

此时,YukiHookAPI 会调用 android.util.Log 与 (Xposed) 宿主环境中的日志功能同时打印这条日志。

日志默认的 TAG 为你在 YLog.Configs.tag 中设置的值。

你也可以动态自定义这个值,但是不建议轻易修改 TAG 防止过滤不到日志。

示例如下

YLog.debug(tag = "YukiHookAPI", msg = "This is a log")

打印的结果为如下所示。

示例如下

[YukiHookAPI][D][宿主包名] This is a log

你还可以使用 YLog.EnvType 自定义日志打印的环境,可选择使用 android.util.Log 还是 (Xposed) 宿主环境中的日志功能来打印日志。

默认类型为 YLog.EnvType.BOTH,含义为同时使用这两个方法来打印日志。

比如我们仅使用 android.util.Log 来打印日志。

示例如下

YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.LOGD)

或仅使用 (Xposed) 宿主环境中的日志功能来打印日志,此方法仅可在 (Xposed) 宿主环境使用。

示例如下

YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.XPOSED_ENVIRONMENT)

若你想智能区分 (Xposed) 宿主环境与模块环境,可以写为如下形式。

示例如下

YLog.debug(tag = "YukiHookAPI", msg = "This is a log", env = YLog.EnvType.SCOPE)

这样 API 就会在不同环境智能选择指定的方法类型去打印这条日志。

小提示

更多功能请参考 YLog.debugYLog.infoYLog.warn 方法。

错误日志

你可以调用 YLog.error 来向控制台打印 E 级别的日志。

使用方法如下所示。

示例如下

YLog.error(msg = "This is an error")

错误日志的级别是最高的,无论你有没有过滤仅为 E 级别的日志。

对于错误级别的日志,你还可以在后面加上一个异常堆栈。

// 假设这就是被抛出的异常
val throwable = Throwable(...)
// 打印日志
YLog.error(msg = "This is an error", e = throwable)

打印的结果为如下所示。

示例如下

[YukiHookAPI][E][宿主包名] This is an error

同时,日志会帮你打印整个异常堆栈。

示例如下

java.lang.Throwable
    at com.demo.Test.<init>(...) 
    at com.demo.Test.doTask(...) 
    at com.demo.Test.stop(...) 
    at com.demo.Test.init(...) 
    at a.a.a(...) 
    ... 3 more

在错误日志中,你同样也可以使用 YLog.EnvType 来指定当前打印日志所用到的方法类型。

小提示

更多功能请参考 YLog.error 方法。

保存日志与自定义元素

你可以使用 YLog.saveToFile 方法直接保存当前已打印的全部日志到文件。

示例如下

// 请注意保存的文件路径必须拥有读写权限,否则会抛出异常
YLog.saveToFile("/sdcard/Documents/debug_log.log")

你还可以使用 YLog.contents 获取当前已打印的全部日志文件内容。

示例如下

// 获取当前已打印的全部日志文件内容
val fileContent = YLog.contents

如果你需要一个实时日志的数据结构数组,你可以直接获取 YLog.inMemoryData 的内容。

示例如下

// 获取当前已打印的实时日志数据结构数组
YLog.inMemoryData.forEach {
    it.timestamp // 获取时间戳
    it.time // 获取 UTC 时间
    it.priority // 获取优先级
    it.msg // 获取消息
    it.throwable // 获取异常
    // ...
}

如果你想对得到的自定义日志数据进行格式化或保存到文件,你只需要使用如下方法即可。

示例如下

// 假设这就是你得到的自定义日志数据
val data: List<YLogData>
// 格式化日志数据到字符串
val dataString = YLog.contents(data)
// 保存日志数据到文件
// 请注意保存的文件路径必须拥有读写权限,否则会抛出异常
YLog.saveToFile("/sdcard/Documents/debug_log.log", data)

特别注意

你需要启用 YLog.Configs.isRecord 才能获取到 YLog.inMemoryData 的内容。

获取到的日志数据在 Hook APP (宿主) 及模块进程中是相互隔离的。

你只能在对应的进程中获取对应的日志数据,如果你需要在任何地方实时得到这些日志数据,请参考 Xposed 模块与宿主通讯桥注册模块 Activity

如果你只想通过模块或宿主来实时得到日志数据,请参考可选方案 YukiHookDataChannel.obtainLoggerInMemoryData 方法。

你还可以使用 YLog.Configs.elements 自定义调试日志对外显示的元素。

此功能需要在 Hook 入口类的 onInit 中对 YukiHookAPI.Configs 进行配置。

示例如下

override fun onInit() = configs {
    debugLog {
        // ...
        elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
    }
    // ...
}

小提示

更多功能请参考 YLog.inMemoryDataYLog.contentsYLog.contentsYLog.saveToFile 方法以及 YLog.Configs