pakstr 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. package/android-template/app/build.gradle.kts +71 -4
  2. package/android-template/app/proguard-rules.pro +21 -18
  3. package/android-template/app/src/main/java/com/pakstr/app/ApplicationClass.kt +14 -0
  4. package/android-template/app/src/main/java/com/pakstr/app/MainActivity.kt +18 -5
  5. package/android-template/app/src/main/java/com/pakstr/app/ShellRuntime.kt +1 -1
  6. package/android-template/app/src/main/java/com/pakstr/app/WebViewController.kt +135 -0
  7. package/android-template/app/src/main/java/com/pakstr/app/debug/AppDebugLogger.kt +78 -5
  8. package/android-template/app/src/main/java/com/pakstr/app/debug/CrashHandler.kt +32 -0
  9. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfigProvider.kt +8 -3
  10. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugLogStorage.kt +43 -11
  11. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugPreferences.kt +85 -0
  12. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugReportExporter.kt +42 -32
  13. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugRuntimeOverride.kt +30 -4
  14. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugSession.kt +16 -0
  15. package/android-template/app/src/main/java/com/pakstr/app/debug/DeveloperToolsManager.kt +42 -13
  16. package/android-template/app/src/main/java/com/pakstr/app/debug/WebViewDebugManager.kt +30 -0
  17. package/android-template/app/src/main/java/com/pakstr/app/debug/logging/PakstrLog.kt +16 -0
  18. package/android-template/app/src/main/java/com/pakstr/app/debug/logging/PakstrLogger.kt +154 -0
  19. package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +1 -1
  20. package/android-template/gradle/libs.versions.toml +1 -0
  21. package/android-template/gradle.properties +2 -1
  22. package/package.json +1 -1
@@ -1,12 +1,59 @@
1
+ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2
+ import java.util.Properties
3
+ import java.io.File
4
+
1
5
  plugins {
2
6
  alias(libs.plugins.android.application)
3
7
  alias(libs.plugins.kotlin.compose)
4
8
  }
5
9
 
10
+ val keystoreProperties =
11
+
12
+ Properties()
13
+
14
+ val keystorePath =
15
+ providers.gradleProperty(
16
+ "releaseKeystoreConfig"
17
+ ).orNull
18
+
19
+ val keystorePropertiesFile =
20
+ keystorePath?.let { rootProject.file(it) }
21
+ if (keystorePropertiesFile?.exists() == true) {
22
+
23
+ keystorePropertiesFile.inputStream()
24
+ .use {
25
+ keystoreProperties.load(it)
26
+ }
27
+ }
28
+
6
29
  android {
7
30
  namespace = "com.pakstr.app"
8
31
  compileSdk = 36
9
32
 
33
+ signingConfigs {
34
+
35
+ create("release") {
36
+
37
+ if (keystorePropertiesFile?.exists() == true) {
38
+
39
+ storeFile =
40
+ File(
41
+ keystorePropertiesFile.parentFile,
42
+ keystoreProperties["storeFile"] as String
43
+ )
44
+
45
+ storePassword =
46
+ keystoreProperties["storePassword"] as String
47
+
48
+ keyAlias =
49
+ keystoreProperties["keyAlias"] as String
50
+
51
+ keyPassword =
52
+ keystoreProperties["keyPassword"] as String
53
+ }
54
+ }
55
+ }
56
+
10
57
  defaultConfig {
11
58
  applicationId = "com.pakstr.app"
12
59
  minSdk = 28
@@ -18,23 +65,43 @@ android {
18
65
  }
19
66
 
20
67
  buildTypes {
68
+
69
+ debug {
70
+ applicationIdSuffix = ".debug"
71
+ versionNameSuffix = "-debug"
72
+ }
73
+
21
74
  release {
22
- isMinifyEnabled = false
75
+ signingConfig =
76
+ signingConfigs.getByName("release")
77
+ isMinifyEnabled = true
78
+ isShrinkResources = true
23
79
  proguardFiles(
24
- getDefaultProguardFile("proguard-android-optimize.txt"),
80
+ getDefaultProguardFile(
81
+ "proguard-android-optimize.txt"
82
+ ),
25
83
  "proguard-rules.pro"
26
84
  )
27
85
  }
28
86
  }
29
87
  compileOptions {
30
- sourceCompatibility = JavaVersion.VERSION_11
31
- targetCompatibility = JavaVersion.VERSION_11
88
+ sourceCompatibility = JavaVersion.VERSION_17
89
+ targetCompatibility = JavaVersion.VERSION_17
32
90
  }
91
+
33
92
  buildFeatures {
34
93
  compose = true
35
94
  buildConfig = true
36
95
  }
37
96
  }
97
+ tasks.withType<KotlinCompile>()
98
+ .configureEach {
99
+ compilerOptions {
100
+ jvmTarget.set(
101
+ org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
102
+ )
103
+ }
104
+ }
38
105
 
39
106
  dependencies {
40
107
  implementation(libs.androidx.core.ktx)
@@ -1,21 +1,24 @@
1
- # Add project specific ProGuard rules here.
2
- # You can control the set of applied configuration files using the
3
- # proguardFiles setting in build.gradle.
4
- #
5
- # For more details, see
6
- # http://developer.android.com/guide/developing/tools/proguard.html
1
+ # JavaScript bridge
2
+ -keepclassmembers class * {
3
+ @android.webkit.JavascriptInterface <methods>;
4
+ }
7
5
 
8
- # If your project uses WebView with JS, uncomment the following
9
- # and specify the fully qualified class name to the JavaScript interface
10
- # class:
11
- #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12
- # public *;
13
- #}
6
+ # Nostr signer
7
+ -keep class com.pakstr.app.signer.** { *; }
14
8
 
15
- # Uncomment this to preserve the line number information for
16
- # debugging stack traces.
17
- #-keepattributes SourceFile,LineNumberTable
9
+ # Crypto
10
+ -keep class com.pakstr.app.crypto.** { *; }
18
11
 
19
- # If you keep the line number information, uncomment this to
20
- # hide the original source file name.
21
- #-renamesourcefileattribute SourceFile
12
+ # BouncyCastle
13
+ -keep class org.bouncycastle.crypto.** { *; }
14
+ -keep class org.bouncycastle.math.** { *; }
15
+ -keep class org.bouncycastle.asn1.** { *; }
16
+
17
+ # Ignore unavailable Java SE classes
18
+ -dontwarn javax.naming.**
19
+
20
+ # Keep Application class
21
+ -keep class com.pakstr.app.ApplicationClass { *; }
22
+
23
+ # Keep model classes used through JSON
24
+ -keep class com.pakstr.app.signer.** { *; }
@@ -2,6 +2,9 @@ package com.pakstr.app
2
2
 
3
3
  import android.app.Application
4
4
  import com.pakstr.app.crypto.CryptoInitializer
5
+ import com.pakstr.app.debug.AppDebugLogger
6
+ import com.pakstr.app.debug.CrashHandler
7
+ import com.pakstr.app.debug.DebugSession
5
8
  import com.pakstr.app.utils.AppPreferences
6
9
 
7
10
  class ApplicationClass : Application() {
@@ -9,5 +12,16 @@ class ApplicationClass : Application() {
9
12
  super.onCreate()
10
13
  AppPreferences.init(this)
11
14
  CryptoInitializer.init()
15
+ CrashHandler.install(this)
16
+
17
+ AppDebugLogger.log(
18
+
19
+ this,
20
+
21
+ "SESSION",
22
+
23
+ "Session started: ${DebugSession.sessionId}"
24
+
25
+ )
12
26
  }
13
27
  }
@@ -18,9 +18,11 @@ import androidx.core.view.ViewCompat
18
18
  import androidx.core.view.WindowInsetsCompat
19
19
  import androidx.core.view.updatePadding
20
20
  import com.pakstr.app.debug.AppDebugLogger
21
+ import com.pakstr.app.debug.CrashHandler
21
22
 
22
23
  import com.pakstr.app.debug.DebugReportShare
23
24
  import com.pakstr.app.debug.DeveloperToolsManager
25
+ import com.pakstr.app.debug.WebViewDebugManager
24
26
 
25
27
  import com.pakstr.app.permissions.PermissionManager
26
28
  import com.pakstr.app.permissions.interfaces.PermissionHandler
@@ -52,21 +54,32 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
52
54
  enableEdgeToEdge()
53
55
 
54
56
  super.onCreate(savedInstanceState)
57
+ if (BuildConfig.DEBUG) {
58
+
59
+ DeveloperToolsManager.enableDebug(this)
60
+
61
+ }
62
+
63
+ WebViewDebugManager.enable(this)
64
+
55
65
  AppDebugLogger.log(
56
66
 
57
67
  this,
58
68
 
59
- "SESSION",
69
+ "TEST",
60
70
 
61
- "========== APP START =========="
71
+ "Developer debug enabled"
62
72
 
63
73
  )
74
+ AppDebugLogger.log(
64
75
 
65
- if (BuildConfig.DEBUG) {
76
+ this,
77
+
78
+ "SESSION",
66
79
 
67
- WebView.setWebContentsDebuggingEnabled(true)
80
+ "========== APP START =========="
68
81
 
69
- }
82
+ )
70
83
 
71
84
  setContentView(
72
85
 
@@ -97,7 +97,7 @@ class ShellRuntime(
97
97
  }
98
98
 
99
99
  }
100
-
100
+ AppDebugLogger.load(context)
101
101
  }
102
102
 
103
103
  private fun startServer(): Boolean {
@@ -95,6 +95,7 @@ class WebViewController(
95
95
  nip07Injected = injectNip07()
96
96
 
97
97
  }
98
+ injectDebugLogger()
98
99
  }
99
100
 
100
101
  override fun onReceivedHttpError(
@@ -343,4 +344,138 @@ class WebViewController(
343
344
  false
344
345
  }
345
346
  }
347
+
348
+ private fun injectDebugLogger() {
349
+
350
+ val js = """
351
+ (function(){
352
+
353
+ if (!window.AndroidBridge) {
354
+ return;
355
+ }
356
+
357
+
358
+ const oldLog = console.log;
359
+ const oldWarn = console.warn;
360
+ const oldError = console.error;
361
+
362
+
363
+ function send(level, args){
364
+
365
+ try {
366
+
367
+ const message =
368
+ Array.from(args)
369
+ .map(item => {
370
+
371
+ if(typeof item === 'object'){
372
+ return JSON.stringify(item);
373
+ }
374
+
375
+ return String(item);
376
+
377
+ })
378
+ .join(" ");
379
+
380
+ window.AndroidBridge.debugLog(
381
+ level,
382
+ message
383
+ );
384
+
385
+ } catch(e){
386
+
387
+ }
388
+ }
389
+
390
+
391
+ console.log = function(){
392
+
393
+ send(
394
+ "LOG",
395
+ arguments
396
+ );
397
+
398
+ oldLog.apply(
399
+ console,
400
+ arguments
401
+ );
402
+ };
403
+
404
+
405
+ console.warn = function(){
406
+
407
+ send(
408
+ "WARN",
409
+ arguments
410
+ );
411
+
412
+ oldWarn.apply(
413
+ console,
414
+ arguments
415
+ );
416
+ };
417
+
418
+
419
+ console.error = function(){
420
+
421
+ send(
422
+ "ERROR",
423
+ arguments
424
+ );
425
+
426
+ oldError.apply(
427
+ console,
428
+ arguments
429
+ );
430
+ };
431
+
432
+
433
+ window.onerror =
434
+ function(
435
+ message,
436
+ source,
437
+ line,
438
+ column,
439
+ error
440
+ ){
441
+
442
+ send(
443
+ "ERROR",
444
+ [
445
+ "JS ERROR:",
446
+ message,
447
+ source,
448
+ line,
449
+ column,
450
+ error?.stack
451
+ ]
452
+ );
453
+
454
+ return false;
455
+ };
456
+
457
+
458
+ window.onunhandledrejection =
459
+ function(event){
460
+
461
+ send(
462
+ "ERROR",
463
+ [
464
+ "PROMISE ERROR:",
465
+ event.reason
466
+ ]
467
+ );
468
+
469
+ };
470
+
471
+
472
+ })();
473
+ """.trimIndent()
474
+
475
+
476
+ webView.evaluateJavascript(
477
+ js,
478
+ null
479
+ )
480
+ }
346
481
  }
@@ -5,6 +5,7 @@ import android.util.Log
5
5
  import com.pakstr.app.BuildConfig
6
6
  import com.pakstr.app.RuntimeConfig
7
7
  import java.text.SimpleDateFormat
8
+ import java.util.Collections
8
9
  import java.util.Date
9
10
  import java.util.Locale
10
11
 
@@ -15,7 +16,12 @@ object AppDebugLogger {
15
16
  private const val MAX_LOGS = 500
16
17
 
17
18
  private val logs =
18
- mutableListOf<String>()
19
+
20
+ Collections.synchronizedList(
21
+
22
+ mutableListOf<String>()
23
+
24
+ )
19
25
 
20
26
  fun log(
21
27
  context: Context,
@@ -108,10 +114,14 @@ object AppDebugLogger {
108
114
 
109
115
  }
110
116
 
111
- fun clear() {
117
+ fun clear(
118
+ context: Context
119
+ ) {
112
120
 
113
121
  logs.clear()
114
122
 
123
+ DebugLogStorage.clear(context)
124
+
115
125
  }
116
126
 
117
127
  private fun isDebugEnabled(
@@ -280,14 +290,77 @@ object AppDebugLogger {
280
290
  }
281
291
 
282
292
  private fun config(
293
+ context: Context
294
+ ): DebugConfig {
295
+
296
+
297
+ val runtime =
298
+ DebugRuntimeOverride.get(context)
299
+
300
+
301
+ if (runtime != null) {
302
+ return runtime
303
+ }
304
+
305
+
306
+ val stored =
307
+ DebugPreferences.load(
308
+ context
309
+ )
310
+
311
+
312
+ if (stored.enabled) {
313
+ return stored
314
+ }
315
+
316
+
317
+ return RuntimeConfig.debugConfig(
318
+ context
319
+ )
320
+
321
+ }
283
322
 
323
+ fun exportLogs(
284
324
  context: Context
325
+ ): String {
285
326
 
286
- ): DebugConfig {
327
+ return buildString {
328
+
329
+ appendLine(
330
+ "===== PAKSTR DEBUG LOG ====="
331
+ )
332
+
333
+ appendLine(
334
+ "Version: ${BuildConfig.VERSION_NAME}"
335
+ )
336
+
337
+ appendLine(
338
+ "Debug: ${isDebugEnabled(context)}"
339
+ )
340
+
341
+ appendLine()
342
+
343
+
344
+ getLogs().forEach {
345
+ appendLine(it)
346
+ }
287
347
 
288
- return DebugRuntimeOverride.get()
348
+ }
349
+ }
350
+
351
+ fun load(
352
+
353
+ context: Context
354
+
355
+ ) {
356
+
357
+ logs.clear()
289
358
 
290
- ?: RuntimeConfig.debugConfig(context)
359
+ logs.addAll(
360
+
361
+ DebugLogStorage.read(context)
362
+
363
+ )
291
364
 
292
365
  }
293
366
  }
@@ -0,0 +1,32 @@
1
+ package com.pakstr.app.debug
2
+
3
+ import android.content.Context
4
+
5
+ object CrashHandler {
6
+
7
+ fun install(
8
+ context: Context
9
+ ) {
10
+
11
+ val defaultHandler =
12
+ Thread.getDefaultUncaughtExceptionHandler()
13
+
14
+
15
+ Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
16
+
17
+
18
+ AppDebugLogger.error(
19
+ context,
20
+ "CRASH",
21
+ "Unhandled exception in ${thread.name}",
22
+ throwable
23
+ )
24
+
25
+
26
+ defaultHandler?.uncaughtException(
27
+ thread,
28
+ throwable
29
+ )
30
+ }
31
+ }
32
+ }
@@ -1,10 +1,13 @@
1
1
  package com.pakstr.app.debug
2
2
 
3
+ import android.content.Context
4
+
3
5
  object DebugConfigProvider {
4
6
 
5
7
  private var manifestConfig =
6
8
  DebugConfig()
7
9
 
10
+
8
11
  fun initialize(
9
12
  config: DebugConfig
10
13
  ) {
@@ -13,10 +16,12 @@ object DebugConfigProvider {
13
16
 
14
17
  }
15
18
 
16
- fun current():
17
- DebugConfig {
18
19
 
19
- return DebugRuntimeOverride.get()
20
+ fun current(
21
+ context: Context
22
+ ): DebugConfig {
23
+
24
+ return DebugRuntimeOverride.get(context)
20
25
  ?: manifestConfig
21
26
 
22
27
  }
@@ -11,6 +11,8 @@ object DebugLogStorage {
11
11
  private const val MAX_FILE_SIZE =
12
12
  1024 * 1024 // 1 MB
13
13
 
14
+ private const val MAX_LINES = 5000
15
+
14
16
  fun append(
15
17
  context: Context,
16
18
  entry: String
@@ -26,9 +28,13 @@ object DebugLogStorage {
26
28
 
27
29
 
28
30
  file.appendText(
31
+
29
32
  entry + "\n"
33
+
30
34
  )
31
35
 
36
+ trimFile(file)
37
+
32
38
  } catch (_: Exception) {
33
39
 
34
40
  // Logging must never crash the app
@@ -38,27 +44,21 @@ object DebugLogStorage {
38
44
 
39
45
  fun read(
40
46
  context: Context
41
- ): String {
47
+ ): List<String> {
42
48
 
43
49
  return try {
44
50
 
45
- val file =
46
- getFile(context)
47
-
51
+ val file = getFile(context)
48
52
 
49
53
  if (file.exists()) {
50
-
51
- file.readText()
52
-
54
+ file.readLines()
53
55
  } else {
54
-
55
- ""
56
-
56
+ emptyList()
57
57
  }
58
58
 
59
59
  } catch (_: Exception) {
60
60
 
61
- ""
61
+ emptyList()
62
62
 
63
63
  }
64
64
  }
@@ -104,4 +104,36 @@ object DebugLogStorage {
104
104
  )
105
105
 
106
106
  }
107
+
108
+ private fun trimFile(
109
+
110
+ file: File
111
+
112
+ ) {
113
+
114
+ try {
115
+
116
+ val lines =
117
+
118
+ file.readLines()
119
+
120
+ if (lines.size > MAX_LINES) {
121
+
122
+ file.writeText(
123
+
124
+ lines
125
+
126
+ .takeLast(MAX_LINES)
127
+
128
+ .joinToString("\n") + "\n"
129
+
130
+ )
131
+
132
+ }
133
+
134
+ } catch (_: Exception) {
135
+
136
+ }
137
+
138
+ }
107
139
  }
@@ -0,0 +1,85 @@
1
+ package com.pakstr.app.debug
2
+
3
+ import android.content.Context
4
+
5
+ object DebugPreferences {
6
+
7
+ private const val PREFS_NAME = "pakstr_debug"
8
+
9
+ private const val KEY_ENABLED = "enabled"
10
+ private const val KEY_NETWORK = "networkLogs"
11
+ private const val KEY_WEBVIEW = "webViewLogs"
12
+
13
+
14
+ private fun prefs(context: Context) =
15
+ context.getSharedPreferences(
16
+ PREFS_NAME,
17
+ Context.MODE_PRIVATE
18
+ )
19
+
20
+
21
+ fun save(
22
+ context: Context,
23
+ config: DebugConfig
24
+ ) {
25
+
26
+ prefs(context)
27
+ .edit()
28
+ .putBoolean(
29
+ KEY_ENABLED,
30
+ config.enabled
31
+ )
32
+ .putBoolean(
33
+ KEY_NETWORK,
34
+ config.networkLogs
35
+ )
36
+ .putBoolean(
37
+ KEY_WEBVIEW,
38
+ config.webViewLogs
39
+ )
40
+ .apply()
41
+
42
+ }
43
+
44
+
45
+ fun load(
46
+ context: Context
47
+ ): DebugConfig {
48
+
49
+ val prefs = prefs(context)
50
+
51
+ return DebugConfig(
52
+
53
+ enabled =
54
+ prefs.getBoolean(
55
+ KEY_ENABLED,
56
+ false
57
+ ),
58
+
59
+ networkLogs =
60
+ prefs.getBoolean(
61
+ KEY_NETWORK,
62
+ false
63
+ ),
64
+
65
+ webViewLogs =
66
+ prefs.getBoolean(
67
+ KEY_WEBVIEW,
68
+ false
69
+ )
70
+
71
+ )
72
+ }
73
+
74
+
75
+ fun clear(
76
+ context: Context
77
+ ) {
78
+
79
+ prefs(context)
80
+ .edit()
81
+ .clear()
82
+ .apply()
83
+
84
+ }
85
+ }
@@ -38,7 +38,7 @@ object DebugReportExporter {
38
38
  val file =
39
39
  File(
40
40
  context.cacheDir,
41
- "pakstr-debug-report.txt"
41
+ "pakstr-debug-report-${DebugSession.sessionId}.txt"
42
42
  )
43
43
 
44
44
 
@@ -57,19 +57,8 @@ object DebugReportExporter {
57
57
 
58
58
 
59
59
  val rawLogs =
60
- if (debugEnabled) {
61
-
62
- DebugLogStorage.read(context)
63
-
64
- } else {
65
-
66
- DebugLogStorage.read(context)
67
- .lines()
68
- .filter {
69
- it.contains("[ERROR]")
70
- }
71
- .joinToString("\n")
72
- }
60
+ DebugLogStorage.read(context)
61
+ .joinToString("\n")
73
62
 
74
63
 
75
64
  val logs =
@@ -77,32 +66,53 @@ object DebugReportExporter {
77
66
 
78
67
 
79
68
  return """
80
- Pakstr Debug Report
81
- ===================
69
+ Pakstr Debug Report
70
+ ===================
71
+
72
+ Session:
73
+ -------------------
74
+ ID:
75
+ ${DebugSession.sessionId}
76
+
77
+ Started:
78
+ ${java.util.Date(DebugSession.startedAt)}
79
+
80
+ Uptime:
81
+ ${DebugSession.uptime()} ms
82
+
83
+
84
+ Application:
85
+ -------------------
86
+ ${BuildConfig.APPLICATION_ID}
87
+
88
+
89
+ Version:
90
+ ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})
91
+
92
+
93
+ Device:
94
+ ${Build.MANUFACTURER} ${Build.MODEL}
95
+
82
96
 
83
- Application:
84
- ${BuildConfig.APPLICATION_ID}
97
+ Android:
98
+ ${Build.VERSION.RELEASE}
85
99
 
86
- Version:
87
- ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})
88
100
 
89
- Device:
90
- ${Build.MANUFACTURER} ${Build.MODEL}
101
+ Debug:
102
+ $debugEnabled
91
103
 
92
- Android:
93
- ${Build.VERSION.RELEASE}
94
104
 
95
- Debug:
96
- $debugEnabled
105
+ API Enabled:
106
+ ${RuntimeConfig.apiEnabled(context)}
97
107
 
98
- API Enabled:
99
- ${RuntimeConfig.apiEnabled(context)}
108
+ WebView Debug:
109
+ ${BuildConfig.DEBUG || RuntimeConfig.debugEnabled(context)}
100
110
 
101
- Logs:
102
- -------------------
103
- $logs
111
+ Logs:
112
+ -------------------
113
+ $logs
104
114
 
105
- """.trimIndent()
115
+ """.trimIndent()
106
116
  }
107
117
 
108
118
 
@@ -1,29 +1,55 @@
1
1
  package com.pakstr.app.debug
2
2
 
3
+ import android.content.Context
4
+
5
+
3
6
  object DebugRuntimeOverride {
4
7
 
5
- private var overrideConfig: DebugConfig? = null
8
+
9
+ private var overrideConfig:
10
+ DebugConfig? = null
6
11
 
7
12
 
8
13
  fun set(
14
+ context: Context,
9
15
  config: DebugConfig
10
16
  ) {
11
17
 
12
18
  overrideConfig = config
13
19
 
20
+ DebugPreferences.save(
21
+ context,
22
+ config
23
+ )
14
24
  }
15
25
 
16
26
 
17
- fun clear() {
27
+ fun clear(
28
+ context: Context
29
+ ) {
18
30
 
19
31
  overrideConfig = null
20
32
 
33
+ DebugPreferences.clear(
34
+ context
35
+ )
21
36
  }
22
37
 
23
38
 
24
- fun get(): DebugConfig? {
39
+ fun get(
40
+ context: Context
41
+ ): DebugConfig? {
25
42
 
26
- return overrideConfig
43
+ if (overrideConfig == null) {
44
+
45
+ val saved =
46
+ DebugPreferences.load(context)
27
47
 
48
+ if (saved.enabled) {
49
+ overrideConfig = saved
50
+ }
51
+ }
52
+
53
+ return overrideConfig
28
54
  }
29
55
  }
@@ -0,0 +1,16 @@
1
+ package com.pakstr.app.debug
2
+
3
+ import java.util.UUID
4
+
5
+ object DebugSession {
6
+
7
+ val sessionId: String =
8
+ UUID.randomUUID().toString()
9
+
10
+ val startedAt: Long =
11
+ System.currentTimeMillis()
12
+
13
+ fun uptime(): Long {
14
+ return System.currentTimeMillis() - startedAt
15
+ }
16
+ }
@@ -1,34 +1,63 @@
1
1
  package com.pakstr.app.debug
2
+
3
+ import android.content.Context
4
+
5
+
2
6
  object DeveloperToolsManager {
3
7
 
4
- fun enableDebug() {
5
8
 
6
- DebugRuntimeOverride.set(
9
+ fun enableDebug(
10
+ context: Context
11
+ ) {
7
12
 
8
- DebugConfig(
13
+ val config = DebugConfig(
9
14
 
10
- enabled = true,
15
+ enabled = true,
11
16
 
12
- networkLogs = true,
17
+ networkLogs = true,
13
18
 
14
- webViewLogs = true,
19
+ webViewLogs = true
20
+
21
+ )
22
+
23
+
24
+
25
+ DebugRuntimeOverride.set(context,
26
+ config
27
+ )
15
28
 
16
- )
29
+ DebugPreferences.save(
30
+ context,
31
+ config
17
32
  )
18
33
 
19
34
  }
20
35
 
21
- fun disableDebug() {
22
36
 
23
- DebugRuntimeOverride.clear()
37
+ fun disableDebug(
38
+ context: Context
39
+ ) {
40
+
41
+
42
+ DebugRuntimeOverride.clear(context)
43
+
44
+
45
+ DebugPreferences.clear(
46
+ context
47
+ )
24
48
 
25
49
  }
26
50
 
27
- fun isEnabled(): Boolean {
28
51
 
29
- return DebugRuntimeOverride.get()
30
- ?.enabled
31
- ?: false
52
+ fun isEnabled(
53
+ context: Context
54
+ ): Boolean {
55
+
56
+
57
+ return DebugPreferences
58
+ .load(context)
59
+ .enabled
32
60
 
33
61
  }
62
+
34
63
  }
@@ -0,0 +1,30 @@
1
+ package com.pakstr.app.debug
2
+
3
+ import android.R.attr.enabled
4
+ import android.content.Context
5
+ import android.webkit.WebView
6
+ import com.pakstr.app.BuildConfig
7
+ import com.pakstr.app.RuntimeConfig
8
+
9
+ object WebViewDebugManager {
10
+
11
+
12
+ fun enable(
13
+ context: Context
14
+ ) {
15
+
16
+ WebView.setWebContentsDebuggingEnabled(
17
+ BuildConfig.DEBUG ||
18
+ RuntimeConfig.debugEnabled(context)
19
+ )
20
+ AppDebugLogger.log(
21
+
22
+ context,
23
+
24
+ "WEBVIEW",
25
+
26
+ "WebView debugging enabled: $enabled"
27
+
28
+ )
29
+ }
30
+ }
@@ -0,0 +1,16 @@
1
+ package com.pakstr.app.debug.logging
2
+
3
+ data class PakstrLog(
4
+ val timestamp: Long,
5
+ val level: Level,
6
+ val tag: String,
7
+ val message: String
8
+ ) {
9
+
10
+ enum class Level {
11
+ DEBUG,
12
+ INFO,
13
+ WARN,
14
+ ERROR
15
+ }
16
+ }
@@ -0,0 +1,154 @@
1
+ package com.pakstr.app.debug.logging
2
+
3
+ import android.util.Log
4
+ import com.pakstr.app.debug.logging.PakstrLog
5
+ import java.text.SimpleDateFormat
6
+ import java.util.Date
7
+ import java.util.Locale
8
+
9
+ object PakstrLogger {
10
+
11
+ private const val MAX_LOGS = 1000
12
+
13
+ private val logs =
14
+ mutableListOf<PakstrLog>()
15
+
16
+
17
+ fun d(
18
+ tag: String,
19
+ message: String
20
+ ) {
21
+ add(
22
+ PakstrLog.Level.DEBUG,
23
+ tag,
24
+ message
25
+ )
26
+
27
+ Log.d(
28
+ "PakstrDebug",
29
+ "[$tag] $message"
30
+ )
31
+ }
32
+
33
+
34
+ fun i(
35
+ tag: String,
36
+ message: String
37
+ ) {
38
+ add(
39
+ PakstrLog.Level.INFO,
40
+ tag,
41
+ message
42
+ )
43
+
44
+ Log.i(
45
+ "PakstrDebug",
46
+ "[$tag] $message"
47
+ )
48
+ }
49
+
50
+
51
+ fun w(
52
+ tag: String,
53
+ message: String
54
+ ) {
55
+ add(
56
+ PakstrLog.Level.WARN,
57
+ tag,
58
+ message
59
+ )
60
+
61
+ Log.w(
62
+ "PakstrDebug",
63
+ "[$tag] $message"
64
+ )
65
+ }
66
+
67
+
68
+ fun e(
69
+ tag: String,
70
+ message: String,
71
+ throwable: Throwable? = null
72
+ ) {
73
+
74
+ add(
75
+ PakstrLog.Level.ERROR,
76
+ tag,
77
+ message
78
+ )
79
+
80
+ Log.e(
81
+ "PakstrDebug",
82
+ "[$tag] $message",
83
+ throwable
84
+ )
85
+ }
86
+
87
+
88
+ fun getLogs(): List<PakstrLog> {
89
+ return logs.toList()
90
+ }
91
+
92
+
93
+ fun clear() {
94
+ logs.clear()
95
+ }
96
+
97
+
98
+ private fun add(
99
+ level: PakstrLog.Level,
100
+ tag: String,
101
+ message: String
102
+ ) {
103
+
104
+ logs.add(
105
+ PakstrLog(
106
+ timestamp =
107
+ System.currentTimeMillis(),
108
+ level = level,
109
+ tag = tag,
110
+ message = message
111
+ )
112
+ )
113
+
114
+
115
+ if (logs.size > MAX_LOGS) {
116
+ logs.removeFirst()
117
+ }
118
+ }
119
+
120
+
121
+ fun exportText(): String {
122
+
123
+ val formatter =
124
+ SimpleDateFormat(
125
+ "yyyy-MM-dd HH:mm:ss",
126
+ Locale.US
127
+ )
128
+
129
+ return buildString {
130
+
131
+ appendLine(
132
+ "Pakstr Debug Report"
133
+ )
134
+
135
+ appendLine(
136
+ "=================="
137
+ )
138
+
139
+ appendLine()
140
+
141
+ logs.forEach {
142
+
143
+ appendLine(
144
+ "${formatter.format(
145
+ Date(it.timestamp)
146
+ )} " +
147
+ "[${it.level}] " +
148
+ "[${it.tag}] " +
149
+ it.message
150
+ )
151
+ }
152
+ }
153
+ }
154
+ }
@@ -435,7 +435,7 @@ class NostrBridge(
435
435
 
436
436
  AppDebugLogger.error(
437
437
  webView.context,
438
- "WEB",
438
+ "WEB-JS",
439
439
  message
440
440
  )
441
441
 
@@ -39,3 +39,4 @@ material = { module = "com.google.android.material:material", version.ref = "mat
39
39
  android-application = { id = "com.android.application", version.ref = "agp" }
40
40
  kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
41
41
 
42
+
@@ -12,4 +12,5 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
12
12
  # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13
13
  # org.gradle.parallel=true
14
14
  # Kotlin code style for this project: "official" or "obsolete":
15
- kotlin.code.style=official
15
+ kotlin.code.style=official
16
+ releaseKeystoreConfig=../../../keystore.properties
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pakstr",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "CLI for packaging Nostr web apps into Android APKs",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",