pakstr 0.0.4 → 0.2.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.
- package/android-template/app/build.gradle.kts +3 -0
- package/android-template/app/src/androidTest/java/com/pakstr/app/ExampleInstrumentedTest.kt +8 -3
- package/android-template/app/src/androidTest/java/com/pakstr/app/signer/NostrEventBuilderTest.kt +67 -0
- package/android-template/app/src/androidTest/java/com/pakstr/app/signer/NostrSignatureVerifierTest.kt +43 -0
- package/android-template/app/src/main/AndroidManifest.xml +15 -3
- package/android-template/app/src/main/assets/nip07.js +85 -4
- package/android-template/app/src/main/assets/www/index.html +215 -0
- package/android-template/app/src/main/java/com/pakstr/app/ApplicationClass.kt +2 -0
- package/android-template/app/src/main/java/com/pakstr/app/LocalServer.kt +35 -10
- package/android-template/app/src/main/java/com/pakstr/app/MainActivity.kt +121 -101
- package/android-template/app/src/main/java/com/pakstr/app/ShellRuntime.kt +5 -6
- package/android-template/app/src/main/java/com/pakstr/app/WebViewController.kt +69 -20
- package/android-template/app/src/main/java/com/pakstr/app/crypto/Bip340Verifier.kt +318 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/CryptoInitializer.kt +34 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/Nip04Crypto.kt +33 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEncryption.kt +16 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEventHasher.kt +100 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEventVerifier.kt +54 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrSignatureVerifier.kt +43 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/Secp256k1.kt +63 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/AppDebugLogger.kt +21 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/AmberSigner.kt +427 -74
- package/android-template/app/src/main/java/com/pakstr/app/signer/BunkerSigner.kt +14 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/FakeSigner.kt +14 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +297 -32
- package/android-template/app/src/main/java/com/pakstr/app/signer/NostrEventBuilder.kt +39 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/SignerManager.kt +103 -73
- package/android-template/app/src/main/java/com/pakstr/app/signer/SignerType.kt +0 -1
- package/android-template/app/src/main/java/com/pakstr/app/signer/exceptions/SignerUnavailableException.kt +5 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/interfaces/NostrSigner.kt +10 -0
- package/android-template/app/src/main/res/values/strings.xml +1 -1
- package/package.json +1 -1
|
@@ -1,153 +1,153 @@
|
|
|
1
1
|
package com.pakstr.app
|
|
2
2
|
|
|
3
3
|
import android.Manifest
|
|
4
|
+
import android.content.Intent
|
|
4
5
|
import android.os.Bundle
|
|
5
6
|
import android.util.Log
|
|
7
|
+
|
|
6
8
|
import android.view.View
|
|
7
9
|
import android.webkit.PermissionRequest
|
|
8
10
|
import android.webkit.WebView
|
|
9
11
|
import android.widget.FrameLayout
|
|
10
12
|
import androidx.activity.OnBackPressedCallback
|
|
11
13
|
import androidx.activity.enableEdgeToEdge
|
|
14
|
+
import androidx.activity.result.ActivityResultLauncher
|
|
12
15
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
13
16
|
import androidx.appcompat.app.AppCompatActivity
|
|
14
17
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
15
18
|
import androidx.core.view.ViewCompat
|
|
16
19
|
import androidx.core.view.WindowInsetsCompat
|
|
17
20
|
import androidx.core.view.updatePadding
|
|
21
|
+
import androidx.lifecycle.lifecycleScope
|
|
18
22
|
import com.pakstr.app.permissions.PermissionManager
|
|
19
23
|
import com.pakstr.app.permissions.interfaces.PermissionHandler
|
|
24
|
+
import com.pakstr.app.crypto.CryptoInitializer
|
|
25
|
+
import com.pakstr.app.debug.AppDebugLogger
|
|
26
|
+
|
|
20
27
|
import com.pakstr.app.signer.SignerManager
|
|
21
|
-
import com.pakstr.app.signer.
|
|
28
|
+
import com.pakstr.app.signer.SignerType
|
|
22
29
|
import com.pakstr.app.utils.AppPreferences
|
|
23
30
|
import com.pakstr.app.utils.SignerPickerBottomSheet
|
|
31
|
+
import kotlinx.coroutines.launch
|
|
24
32
|
|
|
25
33
|
class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
26
34
|
|
|
27
35
|
private lateinit var runtime: ShellRuntime
|
|
28
36
|
private lateinit var container: FrameLayout
|
|
29
37
|
private lateinit var webView: WebView
|
|
30
|
-
|
|
31
38
|
private lateinit var loader: View
|
|
32
|
-
|
|
33
39
|
private lateinit var signerManager: SignerManager
|
|
34
|
-
|
|
35
|
-
private var activeSigner: NostrSigner? = null
|
|
36
|
-
|
|
37
|
-
private var pendingPermissionRequest: PermissionRequest? = null
|
|
38
|
-
|
|
39
40
|
private lateinit var permissionManager: PermissionManager
|
|
41
|
+
private lateinit var amberLauncher:
|
|
42
|
+
ActivityResultLauncher<Intent>
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
ActivityResultContracts.StartActivityForResult()
|
|
46
|
-
|
|
47
|
-
) { result ->
|
|
48
|
-
|
|
49
|
-
signerManager.handleAmberResult(result)
|
|
50
|
-
|
|
51
|
-
}
|
|
44
|
+
override fun onCreate(
|
|
45
|
+
savedInstanceState: Bundle?
|
|
46
|
+
) {
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
val splashScreen = installSplashScreen()
|
|
48
|
+
installSplashScreen()
|
|
55
49
|
enableEdgeToEdge()
|
|
56
50
|
|
|
57
51
|
super.onCreate(savedInstanceState)
|
|
58
|
-
setContentView(R.layout.activity_layout)
|
|
59
52
|
|
|
60
|
-
|
|
53
|
+
if (BuildConfig.DEBUG) {
|
|
61
54
|
|
|
62
|
-
|
|
55
|
+
WebView.setWebContentsDebuggingEnabled(true)
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
) { intent ->
|
|
57
|
+
}
|
|
67
58
|
|
|
68
|
-
|
|
59
|
+
setContentView(
|
|
60
|
+
R.layout.activity_layout
|
|
61
|
+
)
|
|
69
62
|
|
|
70
|
-
|
|
63
|
+
initViews()
|
|
71
64
|
|
|
72
|
-
|
|
65
|
+
amberLauncher =
|
|
66
|
+
registerForActivityResult(
|
|
67
|
+
ActivityResultContracts.StartActivityForResult()
|
|
68
|
+
) { result ->
|
|
69
|
+
signerManager.handleAmberResult(result)
|
|
70
|
+
}
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
initSigner()
|
|
73
|
+
signerManager.setActiveType(
|
|
74
|
+
SignerType.AMBER
|
|
75
|
+
)
|
|
76
|
+
//if (AppPreferences.getBoolean("isFirstRun", true)) {
|
|
77
|
+
//showSignerPicker()
|
|
78
|
+
//}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
ViewCompat.setOnApplyWindowInsetsListener(
|
|
81
|
+
container
|
|
82
|
+
) { view, insets ->
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
val bars =
|
|
85
|
+
insets.getInsets(
|
|
86
|
+
WindowInsetsCompat.Type.systemBars()
|
|
87
|
+
)
|
|
84
88
|
|
|
85
89
|
view.updatePadding(
|
|
86
|
-
top = bars.top,
|
|
90
|
+
top = bars.top,
|
|
91
|
+
bottom = bars.bottom
|
|
87
92
|
)
|
|
88
|
-
|
|
89
93
|
insets
|
|
90
94
|
}
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
signerManager,
|
|
97
|
-
permissionHandler = this
|
|
96
|
+
setupRuntime()
|
|
97
|
+
setupBackNavigation()
|
|
98
|
+
showLoader(true)
|
|
99
|
+
runtime.start()
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
}
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
private fun setupBackNavigation() {
|
|
104
|
+
onBackPressedDispatcher.addCallback(
|
|
105
|
+
this,
|
|
106
|
+
object : OnBackPressedCallback(true) {
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
override fun handleOnBackPressed() {
|
|
104
109
|
|
|
105
|
-
|
|
110
|
+
val currentWebView = runtime.getWebview()
|
|
106
111
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
if (currentWebView.canGoBack()) {
|
|
113
|
+
currentWebView.goBack()
|
|
114
|
+
} else {
|
|
115
|
+
finish()
|
|
116
|
+
}
|
|
111
117
|
}
|
|
112
118
|
}
|
|
113
|
-
|
|
114
|
-
})
|
|
115
|
-
loader.visibility = View.VISIBLE
|
|
116
|
-
runtime.start()
|
|
119
|
+
)
|
|
117
120
|
}
|
|
118
121
|
|
|
119
|
-
private fun
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
private fun setupRuntime() {
|
|
123
|
+
runtime =
|
|
124
|
+
ShellRuntime(
|
|
125
|
+
this,
|
|
126
|
+
webView,
|
|
127
|
+
signerManager,
|
|
128
|
+
permissionHandler = this
|
|
129
|
+
)
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
private fun initSigner() {
|
|
133
|
+
signerManager =
|
|
134
|
+
SignerManager(
|
|
135
|
+
this,
|
|
136
|
+
amberLauncher
|
|
137
|
+
)
|
|
128
138
|
}
|
|
129
139
|
|
|
140
|
+
private fun initViews() {
|
|
130
141
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
activeSigner = signerManager.getSigner()
|
|
138
|
-
|
|
139
|
-
handleSignerSetup()
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
picker.show(
|
|
144
|
-
|
|
145
|
-
supportFragmentManager,
|
|
146
|
-
|
|
147
|
-
"SignerPicker"
|
|
148
|
-
|
|
149
|
-
)
|
|
142
|
+
container =
|
|
143
|
+
findViewById(R.id.mainContainer)
|
|
144
|
+
webView =
|
|
145
|
+
findViewById(R.id.webView)
|
|
146
|
+
loader =
|
|
147
|
+
findViewById(R.id.loader)
|
|
150
148
|
|
|
149
|
+
permissionManager =
|
|
150
|
+
PermissionManager(this)
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
private fun handleSignerSetup() {
|
|
@@ -157,11 +157,24 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
157
157
|
)
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
override fun onDestroy() {
|
|
161
|
+
|
|
162
|
+
if (::runtime.isInitialized) {
|
|
163
|
+
|
|
164
|
+
runtime.stop()
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
super.onDestroy()
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
160
172
|
override fun onRequestPermissionsResult(
|
|
161
173
|
requestCode: Int,
|
|
162
174
|
permissions: Array<out String>,
|
|
163
175
|
grantResults: IntArray
|
|
164
176
|
) {
|
|
177
|
+
|
|
165
178
|
super.onRequestPermissionsResult(
|
|
166
179
|
requestCode,
|
|
167
180
|
permissions,
|
|
@@ -176,33 +189,40 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
|
|
|
176
189
|
override fun onPermissionRequest(
|
|
177
190
|
request: PermissionRequest
|
|
178
191
|
) {
|
|
192
|
+
|
|
179
193
|
permissionManager.request(
|
|
194
|
+
|
|
180
195
|
Manifest.permission.CAMERA
|
|
196
|
+
|
|
181
197
|
) { granted ->
|
|
198
|
+
|
|
182
199
|
if (granted) {
|
|
183
|
-
|
|
200
|
+
|
|
201
|
+
request.grant(
|
|
202
|
+
request.resources
|
|
203
|
+
)
|
|
184
204
|
} else {
|
|
185
205
|
request.deny()
|
|
186
206
|
}
|
|
187
207
|
}
|
|
188
208
|
}
|
|
189
209
|
|
|
190
|
-
private fun
|
|
191
|
-
permissionManager.requestNotificationPermission { granted ->
|
|
192
|
-
|
|
193
|
-
if (granted) {
|
|
194
|
-
Log.d(
|
|
195
|
-
"PERMISSION",
|
|
196
|
-
"Notifications granted"
|
|
197
|
-
)
|
|
198
|
-
} else {
|
|
199
|
-
Log.d(
|
|
200
|
-
"PERMISSION",
|
|
201
|
-
"Notifications denied"
|
|
202
|
-
)
|
|
203
|
-
}
|
|
210
|
+
private fun showSignerPicker() {
|
|
204
211
|
|
|
205
|
-
|
|
212
|
+
SignerPickerBottomSheet { selectedType ->
|
|
213
|
+
signerManager.setActiveType(selectedType)
|
|
214
|
+
handleSignerSetup()
|
|
215
|
+
}.show(
|
|
216
|
+
supportFragmentManager,
|
|
217
|
+
"SignerPicker"
|
|
218
|
+
)
|
|
219
|
+
}
|
|
206
220
|
|
|
221
|
+
private fun showLoader(
|
|
222
|
+
show: Boolean
|
|
223
|
+
) {
|
|
224
|
+
loader.visibility =
|
|
225
|
+
if (show) View.VISIBLE
|
|
226
|
+
else View.GONE
|
|
207
227
|
}
|
|
208
|
-
}
|
|
228
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
package com.pakstr.app
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
-
import
|
|
4
|
+
import com.pakstr.app.debug.AppDebugLogger
|
|
5
5
|
import android.webkit.WebView
|
|
6
6
|
import com.pakstr.app.permissions.interfaces.PermissionHandler
|
|
7
7
|
import com.pakstr.app.signer.SignerManager
|
|
@@ -43,7 +43,7 @@ class ShellRuntime(
|
|
|
43
43
|
|
|
44
44
|
if (!ok) {
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
AppDebugLogger.log(
|
|
47
47
|
"RUNTIME",
|
|
48
48
|
"Server failed"
|
|
49
49
|
)
|
|
@@ -84,7 +84,7 @@ class ShellRuntime(
|
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
AppDebugLogger.log(
|
|
88
88
|
"SERVER",
|
|
89
89
|
"Started OK"
|
|
90
90
|
)
|
|
@@ -96,10 +96,9 @@ class ShellRuntime(
|
|
|
96
96
|
} catch (e: Exception) {
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
AppDebugLogger.log(
|
|
100
100
|
"SERVER",
|
|
101
|
-
"
|
|
102
|
-
e
|
|
101
|
+
"Failed to start: ${e.message}"
|
|
103
102
|
)
|
|
104
103
|
|
|
105
104
|
|
|
@@ -2,7 +2,6 @@ package com.pakstr.app
|
|
|
2
2
|
|
|
3
3
|
import android.app.Activity
|
|
4
4
|
import android.content.Context
|
|
5
|
-
import android.util.Log
|
|
6
5
|
import android.view.View
|
|
7
6
|
import android.webkit.CookieManager
|
|
8
7
|
import android.webkit.PermissionRequest
|
|
@@ -11,11 +10,22 @@ import android.webkit.WebResourceRequest
|
|
|
11
10
|
import android.webkit.WebResourceResponse
|
|
12
11
|
import android.webkit.WebView
|
|
13
12
|
import android.webkit.WebViewClient
|
|
14
|
-
import com.pakstr.app.
|
|
13
|
+
import com.pakstr.app.debug.AppDebugLogger
|
|
15
14
|
import com.pakstr.app.permissions.interfaces.PermissionHandler
|
|
16
15
|
import com.pakstr.app.signer.NostrBridge
|
|
17
16
|
import com.pakstr.app.signer.SignerManager
|
|
18
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Controls WebView configuration and lifecycle.
|
|
20
|
+
*
|
|
21
|
+
* Responsibilities:
|
|
22
|
+
* - Configure secure WebView settings
|
|
23
|
+
* - Load local web application from NanoHTTPD server
|
|
24
|
+
* - Inject NIP-07 JavaScript provider
|
|
25
|
+
* - Expose Android signer bridge to JavaScript
|
|
26
|
+
* - Handle Web permissions
|
|
27
|
+
* - Cleanup WebView resources
|
|
28
|
+
*/
|
|
19
29
|
class WebViewController(
|
|
20
30
|
|
|
21
31
|
private val context: Context,
|
|
@@ -35,6 +45,8 @@ class WebViewController(
|
|
|
35
45
|
//webView.loadUrl("https://sigit.io")
|
|
36
46
|
}
|
|
37
47
|
|
|
48
|
+
private var nip07Injected = false
|
|
49
|
+
|
|
38
50
|
fun setup() {
|
|
39
51
|
showLoader()
|
|
40
52
|
setupWebView()
|
|
@@ -54,21 +66,30 @@ class WebViewController(
|
|
|
54
66
|
|
|
55
67
|
allowFileAccess = false
|
|
56
68
|
allowContentAccess = false
|
|
69
|
+
|
|
70
|
+
mediaPlaybackRequiresUserGesture = false
|
|
71
|
+
builtInZoomControls = false
|
|
72
|
+
displayZoomControls = false
|
|
73
|
+
|
|
74
|
+
mixedContentMode = android.webkit.WebSettings.MIXED_CONTENT_NEVER_ALLOW
|
|
57
75
|
}
|
|
58
76
|
|
|
59
77
|
// Standard clients are enough since overriding URL loading isn't required
|
|
60
78
|
webViewClient = object : WebViewClient() {
|
|
61
79
|
|
|
62
|
-
override fun onPageFinished(
|
|
80
|
+
override fun onPageFinished(
|
|
81
|
+
view: WebView?,
|
|
82
|
+
url: String?
|
|
83
|
+
) {
|
|
63
84
|
super.onPageFinished(view, url)
|
|
64
|
-
hideLoader()
|
|
65
|
-
val js = context.assets.open("nip07.js")
|
|
66
85
|
|
|
67
|
-
|
|
86
|
+
hideLoader()
|
|
68
87
|
|
|
69
|
-
|
|
88
|
+
if (!nip07Injected) {
|
|
89
|
+
nip07Injected =
|
|
90
|
+
injectNip07()
|
|
70
91
|
|
|
71
|
-
|
|
92
|
+
}
|
|
72
93
|
}
|
|
73
94
|
|
|
74
95
|
override fun shouldInterceptRequest(
|
|
@@ -79,12 +100,18 @@ class WebViewController(
|
|
|
79
100
|
|
|
80
101
|
): WebResourceResponse? {
|
|
81
102
|
|
|
82
|
-
val url = request?.url.toString()
|
|
83
|
-
|
|
84
|
-
Log.d("WEB_ASSET", "REQUEST: $url")
|
|
85
|
-
|
|
86
103
|
return super.shouldInterceptRequest(view, request)
|
|
87
104
|
}
|
|
105
|
+
|
|
106
|
+
override fun shouldOverrideUrlLoading(
|
|
107
|
+
view: WebView?,
|
|
108
|
+
request: WebResourceRequest?
|
|
109
|
+
): Boolean {
|
|
110
|
+
val url = request?.url ?: return true
|
|
111
|
+
return url.host != "127.0.0.1"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
88
115
|
}
|
|
89
116
|
webChromeClient = object : WebChromeClient() {
|
|
90
117
|
|
|
@@ -96,13 +123,15 @@ class WebViewController(
|
|
|
96
123
|
}
|
|
97
124
|
}
|
|
98
125
|
|
|
126
|
+
// Exposes native Nostr signer APIs to the WebView.
|
|
127
|
+
// Available in JavaScript as window.AndroidBridge.
|
|
99
128
|
webView.addJavascriptInterface(
|
|
100
129
|
|
|
101
130
|
NostrBridge(
|
|
102
131
|
|
|
103
132
|
signerManager = signerManager,
|
|
104
133
|
|
|
105
|
-
webView = webView
|
|
134
|
+
webView = webView,
|
|
106
135
|
|
|
107
136
|
),
|
|
108
137
|
|
|
@@ -130,13 +159,10 @@ class WebViewController(
|
|
|
130
159
|
fun destroy() {
|
|
131
160
|
webView.stopLoading()
|
|
132
161
|
|
|
133
|
-
webView.clearCache(true)
|
|
134
|
-
|
|
135
162
|
webView.clearHistory()
|
|
136
|
-
|
|
137
|
-
CookieManager.getInstance()
|
|
138
|
-
|
|
139
|
-
CookieManager.getInstance().flush()
|
|
163
|
+
webView.clearCache(false)
|
|
164
|
+
CookieManager.getInstance()
|
|
165
|
+
.flush()
|
|
140
166
|
|
|
141
167
|
webView.loadUrl("about:blank")
|
|
142
168
|
webView.removeCallbacks(loadRunnable)
|
|
@@ -145,4 +171,27 @@ class WebViewController(
|
|
|
145
171
|
|
|
146
172
|
webView.destroy()
|
|
147
173
|
}
|
|
148
|
-
|
|
174
|
+
|
|
175
|
+
private fun injectNip07(): Boolean {
|
|
176
|
+
|
|
177
|
+
return try {
|
|
178
|
+
val js =
|
|
179
|
+
context.assets
|
|
180
|
+
.open("nip07.js")
|
|
181
|
+
.bufferedReader()
|
|
182
|
+
.readText()
|
|
183
|
+
|
|
184
|
+
webView.evaluateJavascript(
|
|
185
|
+
js,
|
|
186
|
+
null
|
|
187
|
+
)
|
|
188
|
+
true
|
|
189
|
+
} catch (e: Exception) {
|
|
190
|
+
AppDebugLogger.log(
|
|
191
|
+
"WEBVIEW",
|
|
192
|
+
"Failed loading nip07.js: ${e.message}"
|
|
193
|
+
)
|
|
194
|
+
false
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|