Added allowed repeat callback in YukiHookDataChannel and fix when activity destroyed, the callback still called

This commit is contained in:
2022-05-26 01:54:35 +08:00
parent 055a86c1ca
commit bc1ca9cdb0
2 changed files with 58 additions and 6 deletions

View File

@@ -1135,6 +1135,48 @@ dataChannel.checkingVersionEquals { isEquals ->
详情请参考 [YukiHookDataChannel](api/document?id=yukihookdatachannel-class)。
### 重复创建回调事件的规则
!> 在模块和宿主中,每一个 `dataChannel` 对应的 `key` 的回调事件**都不允许重复创建**,若重复,之前的回调事件会被新增加的回调事件替换,若在模块中使用,在同一个 `Activity` 中不可以重复,不同的 `Activity` 中相同的 `key` 允许重复。
这里只列出了在模块中使用的例子,在宿主中相同的 `key` 始终不允许重复创建。
> 示例如下
```kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 回调事件 A
dataChannel(packageName = "com.example.demo").wait(key = "test_key") {
// Your code here.
}
// 回调事件 B
dataChannel(packageName = "com.example.demo").wait(key = "test_key") {
// Your code here.
}
// 回调事件 C
dataChannel(packageName = "com.example.demo").wait(key = "other_test_key") {
// Your code here.
}
}
}
class OtherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 回调事件 D
dataChannel(packageName = "com.example.demo").wait(key = "test_key") {
// Your code here.
}
}
}
```
在上述示例中,回调事件 A 会被回调事件 B 替换掉,回调事件 C 的 `key` 不与其它重复,回调事件 D 在另一个 Activity 中,所以最终回调事件 B、C、D 都可被创建成功。
## 宿主生命周期扩展功能
> 这是一个自动 Hook 宿主 APP 生命周期的扩展功能。

View File

@@ -29,6 +29,7 @@
package com.highcapable.yukihookapi.hook.xposed.channel
import android.app.Activity
import android.app.Application
import android.content.BroadcastReceiver
import android.content.Context
@@ -38,7 +39,6 @@ import android.os.Bundle
import android.os.Parcelable
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.utils.putIfAbsentCompat
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
@@ -83,7 +83,7 @@ class YukiHookDataChannel private constructor() {
}
/** 注册广播回调数组 */
private var receiverCallbacks = HashMap<String, ((String, Intent) -> Unit)>()
private var receiverCallbacks = HashMap<String, Pair<Context?, (String, Intent) -> Unit>>()
/** 当前注册广播的 [Context] */
private var receiverContext: Context? = null
@@ -93,7 +93,17 @@ class YukiHookDataChannel private constructor() {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent == null) return
intent.action?.also { action -> receiverCallbacks.takeIf { it.isNotEmpty() }?.forEach { (_, it) -> it(action, intent) } }
intent.action?.also { action ->
receiverCallbacks.takeIf { it.isNotEmpty() }?.apply {
val destroyedCallbacks = arrayListOf<String>()
forEach { (key, it) ->
if (it.first is Activity && (it.first as? Activity?)?.isDestroyed == true)
destroyedCallbacks.add(key)
else it.second(action, intent)
}
destroyedCallbacks.takeIf { it.isNotEmpty() }?.forEach { remove(it) }
}
}
}
}
}
@@ -201,7 +211,7 @@ class YukiHookDataChannel private constructor() {
* @param result 回调结果数据
*/
fun <T> wait(key: String, value: T? = null, result: (value: T) -> Unit) {
receiverCallbacks.putIfAbsentCompat(key) { action, intent ->
receiverCallbacks[key + "_single_" + context?.javaClass?.name] = Pair(context) { action, intent ->
if (action == if (isXposedEnvironment) hostActionName(packageName) else moduleActionName(context))
(intent.extras?.get(key) as? T?).also { if (it != null || value != null) (it ?: value)?.let { e -> result(e) } }
}
@@ -214,7 +224,7 @@ class YukiHookDataChannel private constructor() {
* @param result 回调结果数据
*/
fun <T> wait(data: ChannelData<T>, value: T? = data.value, result: (value: T) -> Unit) {
receiverCallbacks.putIfAbsentCompat(data.key) { action, intent ->
receiverCallbacks[data.key + "_cdata_" + context?.javaClass?.name] = Pair(context) { action, intent ->
if (action == if (isXposedEnvironment) hostActionName(packageName) else moduleActionName(context))
(intent.extras?.get(data.key) as? T?).also { if (it != null || value != null) (it ?: value)?.let { e -> result(e) } }
}
@@ -228,7 +238,7 @@ class YukiHookDataChannel private constructor() {
* @param result 回调结果
*/
fun wait(key: String, result: () -> Unit) {
receiverCallbacks.putIfAbsentCompat(key) { action, intent ->
receiverCallbacks[key + "_vwfl_" + context?.javaClass?.name] = Pair(context) { action, intent ->
if (action == if (isXposedEnvironment) hostActionName(packageName) else moduleActionName(context))
if (intent.getStringExtra(key) == VALUE_WAIT_FOR_LISTENER) result()
}