Skip to content

Commit f64fcc6

Browse files
authored
freeRASP: 7.2.2 (#181)
* fix: crashing sdk caused by screen protector * chore: raise min version in example app * chore: update changelog * chore: raise version * chore: raise version
1 parent f41a729 commit f64fcc6

File tree

5 files changed

+88
-58
lines changed

5 files changed

+88
-58
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [7.2.2] - 2025-10-09
9+
- iOS SDK version: 6.12.1
10+
- Android SDK version: 16.0.1
11+
12+
### Android
13+
14+
#### Fixed
15+
- Fixed an issue with crashing screen protector
16+
817
## [7.2.1] - 2025-07-18
918
- iOS SDK version: 6.12.1
1019
- Android SDK version: 16.0.1

android/src/main/kotlin/com/aheaditec/freerasp/FreeraspPlugin.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.aheaditec.freerasp
22

3+
import android.app.Activity
34
import android.content.Context
45
import android.os.Build
56
import androidx.lifecycle.Lifecycle
@@ -18,15 +19,15 @@ class FreeraspPlugin : FlutterPlugin, ActivityAware, LifecycleEventObserver {
1819
private var streamHandler: StreamHandler = StreamHandler()
1920
private var methodCallHandler: MethodCallHandler = MethodCallHandler()
2021
private var screenProtector: ScreenProtector? =
21-
if (Build.VERSION.SDK_INT >= 34) ScreenProtector() else null
22+
if (Build.VERSION.SDK_INT >= 34) ScreenProtector else null
2223

2324
private var context: Context? = null
2425
private var lifecycle: Lifecycle? = null
26+
private var activity: Activity? = null
2527

2628
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
2729
val messenger = flutterPluginBinding.binaryMessenger
2830
context = flutterPluginBinding.applicationContext
29-
screenProtector?.enable()
3031
methodCallHandler.createMethodChannel(messenger, flutterPluginBinding.applicationContext)
3132
streamHandler.createEventChannel(messenger)
3233
}
@@ -41,32 +42,31 @@ class FreeraspPlugin : FlutterPlugin, ActivityAware, LifecycleEventObserver {
4142
lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding).also {
4243
it.addObserver(this)
4344
}
45+
screenProtector?.register(binding.activity)
4446
methodCallHandler.activity = binding.activity
45-
screenProtector?.activity = binding.activity
46-
screenProtector?.let { lifecycle?.addObserver(it) }
47+
activity = binding.activity
4748
}
4849

4950
override fun onDetachedFromActivity() {
5051
lifecycle?.removeObserver(this)
52+
screenProtector?.unregister(activity!!)
5153
methodCallHandler.activity = null
52-
screenProtector?.let { lifecycle?.removeObserver(it) }
53-
screenProtector?.activity = null
54+
activity = null
5455
}
5556

5657
override fun onDetachedFromActivityForConfigChanges() {
5758
lifecycle?.removeObserver(this)
59+
screenProtector?.unregister(activity!!)
5860
methodCallHandler.activity = null
59-
screenProtector?.let { lifecycle?.removeObserver(it) }
60-
screenProtector?.activity = null
61+
activity = null
6162
}
6263

6364
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
6465
lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding)
65-
lifecycle?.addObserver(this)
66+
activity = binding.activity
6667
methodCallHandler.activity = binding.activity
67-
screenProtector?.activity = binding.activity
68-
screenProtector?.let { lifecycle?.addObserver(it) }
69-
68+
lifecycle?.addObserver(this)
69+
screenProtector?.register(binding.activity)
7070
}
7171

7272
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {

android/src/main/kotlin/com/aheaditec/freerasp/ScreenProtector.kt

Lines changed: 63 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,70 +15,48 @@ import com.aheaditec.talsec_security.security.api.Talsec
1515
import io.flutter.Log
1616
import java.util.function.Consumer
1717

18-
internal class ScreenProtector : DefaultLifecycleObserver {
19-
companion object {
20-
private const val TAG = "ScreenProtector"
21-
private const val SCREEN_CAPTURE_PERMISSION = "android.permission.DETECT_SCREEN_CAPTURE"
22-
private const val SCREEN_RECORDING_PERMISSION = "android.permission.DETECT_SCREEN_RECORDING"
23-
}
18+
@SuppressLint("StaticFieldLeak")
19+
internal object ScreenProtector {
20+
private const val TAG = "TalsecScreenProtector"
21+
private const val SCREEN_CAPTURE_PERMISSION = "android.permission.DETECT_SCREEN_CAPTURE"
22+
private const val SCREEN_RECORDING_PERMISSION = "android.permission.DETECT_SCREEN_RECORDING"
2423

25-
internal var activity: Activity? = null
2624
private var isEnabled = false
25+
private var isRegistered = false
2726

28-
private val screenCaptureCallback = ScreenCaptureCallback { Talsec.onScreenshotDetected() }
27+
private val cachedThreats = mutableSetOf<Threat>()
28+
private val screenCaptureCallback = ScreenCaptureCallback { handleThreat(Threat.Screenshot) }
2929
private val screenRecordCallback: Consumer<Int> = Consumer<Int> { state ->
30-
if (state == SCREEN_RECORDING_STATE_VISIBLE) {
31-
Talsec.onScreenRecordingDetected()
32-
Log.e("ScreenProtector", "Screen recording detected")
33-
}
30+
if (state == SCREEN_RECORDING_STATE_VISIBLE) handleThreat(Threat.ScreenRecording)
3431
}
3532

36-
internal fun enable() {
33+
fun enable() {
3734
if (isEnabled) return
35+
3836
isEnabled = true
37+
cachedThreats.forEach { handleThreat(it) }
38+
cachedThreats.clear()
3939
}
4040

41-
override fun onStart(owner: LifecycleOwner) {
42-
super.onStart(owner)
43-
44-
if (isEnabled) activity?.let { register(it) }
41+
fun disable() {
42+
isEnabled = false
4543
}
4644

47-
override fun onStop(owner: LifecycleOwner) {
48-
super.onStop(owner)
49-
50-
if (isEnabled) activity?.let { unregister(it) }
51-
}
45+
internal fun register(activity: Activity) {
46+
if (isRegistered) {
47+
android.util.Log.w(TAG, "ScreenProtector is already registered.")
48+
return
49+
}
5250

53-
private fun register(activity: Activity) {
5451
if (Build.VERSION.SDK_INT >= 34) {
5552
registerScreenCapture(activity)
5653
}
5754

5855
if (Build.VERSION.SDK_INT >= 35) {
5956
registerScreenRecording(activity)
6057
}
61-
}
62-
63-
// Missing permission is suppressed because the decision to use the screen capture API is made
64-
// by developer, and not enforced by the library.
65-
@SuppressLint("MissingPermission")
66-
private fun unregister(currentActivity: Activity) {
67-
val context = currentActivity.applicationContext
68-
69-
if (Build.VERSION.SDK_INT >= 34 && hasPermission(
70-
context, SCREEN_CAPTURE_PERMISSION
71-
)
72-
) {
73-
currentActivity.unregisterScreenCaptureCallback(screenCaptureCallback)
74-
}
7558

76-
if (Build.VERSION.SDK_INT >= 35 && hasPermission(
77-
context, SCREEN_RECORDING_PERMISSION
78-
)
79-
) {
80-
currentActivity.windowManager?.removeScreenRecordingCallback(screenRecordCallback)
81-
}
59+
isRegistered = true
8260
}
8361

8462
// Missing permission is suppressed because the decision to use the screen capture API is made
@@ -112,7 +90,34 @@ internal class ScreenProtector : DefaultLifecycleObserver {
11290
context.mainExecutor, screenRecordCallback
11391
)
11492
screenRecordCallback.accept(initialState)
93+
}
11594

95+
// Missing permission is suppressed because the decision to use the screen capture API is made
96+
// by developer, and not enforced by the library.
97+
@SuppressLint("MissingPermission")
98+
internal fun unregister(currentActivity: Activity) {
99+
if (!isRegistered) {
100+
android.util.Log.w(TAG, "ScreenProtector is not registered.")
101+
return
102+
}
103+
104+
val context = currentActivity.applicationContext
105+
106+
if (Build.VERSION.SDK_INT >= 34 && hasPermission(
107+
context, SCREEN_CAPTURE_PERMISSION
108+
)
109+
) {
110+
currentActivity.unregisterScreenCaptureCallback(screenCaptureCallback)
111+
}
112+
113+
if (Build.VERSION.SDK_INT >= 35 && hasPermission(
114+
context, SCREEN_RECORDING_PERMISSION
115+
)
116+
) {
117+
currentActivity.windowManager?.removeScreenRecordingCallback(screenRecordCallback)
118+
}
119+
120+
isRegistered = false
116121
}
117122

118123
private fun hasPermission(context: Context, permission: String): Boolean {
@@ -122,9 +127,22 @@ internal class ScreenProtector : DefaultLifecycleObserver {
122127
}
123128

124129
private fun reportMissingPermission(protectionType: String, permission: String) {
125-
Log.e(
130+
android.util.Log.e(
126131
TAG,
127132
"Failed to register $protectionType callback. Check if $permission permission is granted in AndroidManifest.xml"
128133
)
129134
}
130-
}
135+
136+
private fun handleThreat(threat: Threat) {
137+
if (!isEnabled) {
138+
cachedThreats.add(threat)
139+
return
140+
}
141+
142+
when (threat) {
143+
Threat.Screenshot -> Talsec.onScreenshotDetected()
144+
Threat.ScreenRecording -> Talsec.onScreenRecordingDetected()
145+
else -> throw IllegalArgumentException("Unexpected Threat type: $threat")
146+
}
147+
}
148+
}

android/src/main/kotlin/com/aheaditec/freerasp/handlers/TalsecThreatHandler.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ internal object TalsecThreatHandler {
2626
internal fun start(context: Context, config: TalsecConfig) {
2727
attachListener(context)
2828
Talsec.start(context, config)
29+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
30+
ScreenProtector.enable()
31+
}
2932
}
3033

3134
/**

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: freerasp
22
description: Flutter library for improving app security and threat monitoring on Android and iOS mobile devices. Learn more about provided features on the freeRASP's homepage first.
3-
version: 7.2.1
3+
version: 7.2.2
44
homepage: https://www.talsec.app/freerasp-in-app-protection-security-talsec
55
repository: https://github.com/talsec/Free-RASP-Flutter
66

0 commit comments

Comments
 (0)