diff --git a/.gitignore b/.gitignore
index 5f84ec3cf..a8e20f69b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,3 +58,6 @@ nkn.aar
**.p12
**.cer
/android/app/.cxx/
+/.env
+
+/lib/upgrade/appcast.json
diff --git a/android/.gitignore b/android/.gitignore
index bcca131af..1bfdca243 100644
--- a/android/.gitignore
+++ b/android/.gitignore
@@ -8,3 +8,4 @@ GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+/build/
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 7c033d263..26dcd03ee 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -8,7 +8,7 @@ plugins {
android {
namespace = "org.nkn.mobile.app"
- compileSdk = 35
+ compileSdk = 36
ndkVersion = "27.0.12077973"
compileOptions {
@@ -27,7 +27,7 @@ android {
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 24
- targetSdk = flutter.targetSdkVersion
+ targetSdk = 36
versionCode = flutter.versionCode
versionName = flutter.versionName
}
@@ -72,7 +72,9 @@ dependencies {
implementation("androidx.window:window:1.3.0")
implementation("androidx.window:window-java:1.3.0")
// google
- implementation("com.google.firebase:firebase-messaging:24.1.1")
+ implementation(platform("com.google.firebase:firebase-bom:34.1.0"))
+ implementation("com.google.firebase:firebase-analytics")
+ implementation("com.google.firebase:firebase-messaging")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:mockwebserver:4.12.0")
implementation("com.squareup.okhttp3:okhttp-tls:4.10.0")
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
new file mode 100644
index 000000000..d0e0fbc9b
--- /dev/null
+++ b/android/app/proguard-rules.pro
@@ -0,0 +1 @@
+-keep class net.sqlcipher.** { *; }
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6fb3216ec..b47803a51 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -101,33 +101,27 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -138,16 +132,18 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -177,10 +173,6 @@
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/ic_launcher_round" />
-
-
-
-
diff --git a/android/app/src/main/kotlin/org/nkn/mobile/app/MainActivity.kt b/android/app/src/main/kotlin/org/nkn/mobile/app/MainActivity.kt
index d97704ce2..5b152f2b4 100644
--- a/android/app/src/main/kotlin/org/nkn/mobile/app/MainActivity.kt
+++ b/android/app/src/main/kotlin/org/nkn/mobile/app/MainActivity.kt
@@ -10,6 +10,7 @@ import io.flutter.plugins.GeneratedPluginRegistrant
import org.nkn.mobile.app.channels.impl.Common
import org.nkn.mobile.app.channels.impl.nameService.DnsResolver
import org.nkn.mobile.app.channels.impl.nameService.EthResolver
+import org.nkn.mobile.app.channels.impl.searchService.SearchService
import org.nkn.mobile.app.crypto.Crypto
import org.nkn.mobile.app.push.APNSPush
@@ -74,6 +75,7 @@ class MainActivity : FlutterFragmentActivity() {
Crypto.register(flutterEngine)
EthResolver.register(flutterEngine)
DnsResolver.register(flutterEngine)
+ SearchService.register(flutterEngine)
APNSPush.openClient(assets)
}
diff --git a/android/app/src/main/kotlin/org/nkn/mobile/app/channels/impl/searchService/Search.kt b/android/app/src/main/kotlin/org/nkn/mobile/app/channels/impl/searchService/Search.kt
new file mode 100644
index 000000000..b162b2e4b
--- /dev/null
+++ b/android/app/src/main/kotlin/org/nkn/mobile/app/channels/impl/searchService/Search.kt
@@ -0,0 +1,379 @@
+package org.nkn.mobile.app.channels.impl.searchService
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.EventChannel
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import org.nkn.mobile.app.channels.IChannelHandler
+import search.Search
+import java.util.UUID
+import java.util.concurrent.ConcurrentHashMap
+
+class SearchService : IChannelHandler, MethodChannel.MethodCallHandler, EventChannel.StreamHandler, ViewModel() {
+
+ companion object {
+ lateinit var methodChannel: MethodChannel
+ const val METHOD_CHANNEL_NAME = "org.nkn.mobile/native/search"
+
+ lateinit var eventChannel: EventChannel
+ const val EVENT_CHANNEL_NAME = "org.nkn.mobile/native/search_event"
+ private var eventSink: EventChannel.EventSink? = null
+
+ // Store search client instances by ID
+ private val clients = ConcurrentHashMap()
+
+ fun register(flutterEngine: FlutterEngine) {
+ SearchService().install(flutterEngine.dartExecutor.binaryMessenger)
+ }
+ }
+
+ override fun install(binaryMessenger: BinaryMessenger) {
+ methodChannel = MethodChannel(binaryMessenger, METHOD_CHANNEL_NAME)
+ methodChannel.setMethodCallHandler(this)
+ eventChannel = EventChannel(binaryMessenger, EVENT_CHANNEL_NAME)
+ eventChannel.setStreamHandler(this)
+ }
+
+ override fun uninstall() {
+ methodChannel.setMethodCallHandler(null)
+ eventChannel.setStreamHandler(null)
+ }
+
+ override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
+ eventSink = events
+ }
+
+ override fun onCancel(arguments: Any?) {
+ eventSink = null
+ }
+
+ override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
+ when (call.method) {
+ "newSearchClient" -> newSearchClient(call, result)
+ "newSearchClientWithAuth" -> newSearchClientWithAuth(call, result)
+ "query" -> query(call, result)
+ "submitUserData" -> submitUserData(call, result)
+ "verify" -> verify(call, result)
+ "queryByID" -> queryByID(call, result)
+ "getMyInfo" -> getMyInfo(call, result)
+ "getPublicKeyHex" -> getPublicKeyHex(call, result)
+ "getAddress" -> getAddress(call, result)
+ "isVerified" -> isVerified(call, result)
+ "disposeClient" -> disposeClient(call, result)
+ else -> result.notImplemented()
+ }
+ }
+
+ // Create a query-only search client
+ private fun newSearchClient(call: MethodCall, result: MethodChannel.Result) {
+ val apiBase = call.argument("apiBase") ?: ""
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val client = Search.newSearchClient(apiBase)
+ if (client == null) {
+ resultError(result, "CREATE_CLIENT_FAILED", "Failed to create search client")
+ return@launch
+ }
+
+ // Generate unique ID for this client
+ val clientId = UUID.randomUUID().toString()
+ clients[clientId] = client
+
+ val response = hashMapOf(
+ "clientId" to clientId
+ )
+
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Create an authenticated search client
+ private fun newSearchClientWithAuth(call: MethodCall, result: MethodChannel.Result) {
+ val apiBase = call.argument("apiBase") ?: ""
+ val seed = call.argument("seed")
+
+ if (seed == null || seed.size != 32) {
+ viewModelScope.launch(Dispatchers.IO) {
+ resultError(result, "INVALID_SEED", "Seed must be exactly 32 bytes")
+ }
+ return
+ }
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val client = Search.newSearchClientWithAuth(apiBase, seed)
+ if (client == null) {
+ resultError(result, "CREATE_AUTH_CLIENT_FAILED", "Failed to create authenticated search client")
+ return@launch
+ }
+
+ // Generate unique ID for this client
+ val clientId = UUID.randomUUID().toString()
+ clients[clientId] = client
+
+ val response = hashMapOf(
+ "clientId" to clientId
+ )
+
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Query data by keyword
+ private fun query(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+ val keyword = call.argument("keyword") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.IO) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val response = client.query(keyword)
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Submit user data
+ private fun submitUserData(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+ var nknAddress = call.argument("nknAddress") ?: ""
+ val customId = call.argument("customId") ?: ""
+ val nickname = call.argument("nickname") ?: ""
+ val phoneNumber = call.argument("phoneNumber") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.Default) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ // Use Dispatchers.Default for CPU-intensive PoW calculation
+ // Default dispatcher is optimized for CPU-bound work
+ viewModelScope.launch(Dispatchers.Default) {
+ try {
+ // Process nknAddress: if empty, use publicKey
+ val publicKeyHex = client.publicKeyHex ?: ""
+
+ if (nknAddress.isEmpty()) {
+ nknAddress = publicKeyHex
+ } else {
+ // Validate format if contains dot
+ if (nknAddress.contains(".")) {
+ val parts = nknAddress.split(".")
+ if (parts.size != 2) {
+ resultError(result, "INVALID_PARAMETER",
+ "Invalid nknAddress format. Expected: identifier.publickey")
+ return@launch
+ }
+ val providedPubKey = parts[1]
+ if (providedPubKey.lowercase() != publicKeyHex.lowercase()) {
+ resultError(result, "INVALID_PARAMETER",
+ "nknAddress publickey suffix must match your actual publicKey")
+ return@launch
+ }
+ } else {
+ // If no dot, must equal publicKey
+ if (nknAddress.lowercase() != publicKeyHex.lowercase()) {
+ resultError(result, "INVALID_PARAMETER",
+ "nknAddress must be either \"identifier.publickey\" format or equal to publicKey")
+ return@launch
+ }
+ }
+ }
+
+ // Validate customId if provided
+ if (customId.isNotEmpty() && customId.length < 3) {
+ resultError(result, "INVALID_PARAMETER",
+ "customId must be at least 3 characters if provided")
+ return@launch
+ }
+
+ client.submitUserData(nknAddress, customId, nickname, phoneNumber)
+ val response = hashMapOf(
+ "success" to true
+ )
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Verify the client (optional, for query operations)
+ private fun verify(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.Default) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ // Use Dispatchers.Default for CPU-intensive PoW calculation
+ viewModelScope.launch(Dispatchers.Default) {
+ try {
+ client.verify()
+ val response = hashMapOf(
+ "success" to true
+ )
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Query by ID
+ private fun queryByID(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+ val id = call.argument("id") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.IO) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val response = client.queryByID(id)
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Get my info by nknAddress
+ private fun getMyInfo(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+ val address = call.argument("address") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.IO) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val response = client.getMyInfo(address)
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Get public key hex
+ private fun getPublicKeyHex(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.IO) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val publicKeyHex = client.publicKeyHex
+ resultSuccess(result, publicKeyHex)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Get wallet address
+ private fun getAddress(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.IO) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val address = client.address
+ resultSuccess(result, address)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Check if verified
+ private fun isVerified(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+
+ val client = clients[clientId]
+ if (client == null) {
+ viewModelScope.launch(Dispatchers.IO) {
+ resultError(result, "CLIENT_NOT_FOUND", "Search client not found")
+ }
+ return
+ }
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ val verified = client.isVerified
+ resultSuccess(result, verified)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+
+ // Dispose client
+ private fun disposeClient(call: MethodCall, result: MethodChannel.Result) {
+ val clientId = call.argument("clientId") ?: ""
+
+ viewModelScope.launch(Dispatchers.IO) {
+ try {
+ clients.remove(clientId)
+ val response = hashMapOf(
+ "success" to true
+ )
+ resultSuccess(result, response)
+ } catch (e: Exception) {
+ resultError(result, e)
+ }
+ }
+ }
+}
diff --git a/android/build.gradle.kts b/android/build.gradle.kts
index aeb91d75b..7f8edd7b9 100644
--- a/android/build.gradle.kts
+++ b/android/build.gradle.kts
@@ -4,8 +4,8 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath("com.android.tools.build:gradle:8.1.4")
- classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
+ classpath("com.android.tools.build:gradle:8.12.3")
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.21")
}
}
@@ -39,7 +39,7 @@ subprojects {
}
val javaVersion = JavaVersion.VERSION_21
- val androidApiVersion = 35
+ val androidApiVersion = 36
android.compileSdkVersion(androidApiVersion)
android.defaultConfig.targetSdk = androidApiVersion
@@ -48,8 +48,10 @@ subprojects {
android.compileOptions.targetCompatibility = javaVersion
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class.java).configureEach {
- kotlinOptions {
- jvmTarget = javaVersion.toString()
+ compilerOptions {
+ jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
+ languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
+ apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_2)
}
}
diff --git a/android/gradle.properties b/android/gradle.properties
index e8e664173..24863d218 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,4 +1,3 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
-android.enableJetifier=true
-android.enableR8=true
\ No newline at end of file
+android.enableJetifier=true
\ No newline at end of file
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index efdcc4ace..02767eb1c 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts
index b51a5bde6..b450fd7f9 100644
--- a/android/settings.gradle.kts
+++ b/android/settings.gradle.kts
@@ -18,8 +18,8 @@ pluginManagement {
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
- id("com.android.application") version "8.9.1" apply false
- id("org.jetbrains.kotlin.android") version "2.0.0" apply false
+ id("com.android.application") version "8.12.3" apply false
+ id("org.jetbrains.kotlin.android") version "2.2.21" apply false
}
include(":app")
diff --git a/assets/icons/smile.svg b/assets/icons/smile.svg
new file mode 100644
index 000000000..6eb9964d7
--- /dev/null
+++ b/assets/icons/smile.svg
@@ -0,0 +1,6 @@
+
diff --git a/devtools_options.yaml b/devtools_options.yaml
new file mode 100644
index 000000000..fa0b357c4
--- /dev/null
+++ b/devtools_options.yaml
@@ -0,0 +1,3 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
diff --git a/golib/Makefile b/golib/Makefile
index c19b1c22e..de1c09536 100644
--- a/golib/Makefile
+++ b/golib/Makefile
@@ -5,15 +5,15 @@ GOMOBILE=gomobile
GOBIND=$(GOMOBILE) bind
BUILDDIR=$(shell pwd)/build
IMPORT_PATH=nkn
-LDFLAGS='-s -w'
-ANDROID_LDFLAGS='-s -w'
+LDFLAGS='-s -w -extldflags=-lresolv -checklinkname=0'
+ANDROID_LDFLAGS='-s -w -extldflags=-Wl,-z,max-page-size=16384 -checklinkname=0'
ANDROID_BUILDDIR=$(BUILDDIR)/android
ANDROID_ARTIFACT=$(ANDROID_BUILDDIR)/nkn.aar
IOS_BUILDDIR=$(BUILDDIR)/ios
IOS_ARTIFACT=$(IOS_BUILDDIR)/Nkn.xcframework
-BUILD_PACKAGE=./ ./crypto github.com/nknorg/nkn-sdk-go github.com/nknorg/ncp-go github.com/nknorg/nkn/v2/transaction github.com/nknorg/nkngomobile github.com/nknorg/reedsolomon github.com/nknorg/eth-resolver-go github.com/nknorg/dns-resolver-go
+BUILD_PACKAGE=./ ./crypto ./search github.com/nknorg/nkn-sdk-go github.com/nknorg/ncp-go github.com/nknorg/nkn/v2/transaction github.com/nknorg/nkngomobile github.com/nknorg/reedsolomon github.com/nknorg/eth-resolver-go github.com/nknorg/dns-resolver-go
ANDROID_BUILD_CMD="$(GOBIND) -ldflags $(ANDROID_LDFLAGS) -target=android -androidapi=21 -o $(ANDROID_ARTIFACT) $(BUILD_PACKAGE)"
IOS_BUILD_CMD="$(GOBIND) -ldflags $(LDFLAGS) -target=ios -o $(IOS_ARTIFACT) $(BUILD_PACKAGE)"
diff --git a/golib/go.mod b/golib/go.mod
index 6a58d253e..e8cf9e540 100644
--- a/golib/go.mod
+++ b/golib/go.mod
@@ -1,15 +1,17 @@
module nkngolib
-go 1.18
+go 1.22.0
+
+toolchain go1.22.2
require (
- github.com/nknorg/dns-resolver-go v0.0.0-20220705102626-b041cd8d4a8e
+ github.com/nknorg/dns-resolver-go v0.0.0-20230404043755-e50d32d9043a
github.com/nknorg/eth-resolver-go v0.0.0-20230404061427-d0bd773f899f
- github.com/nknorg/ncp-go v1.0.5 // indirect
- github.com/nknorg/nkn-sdk-go v1.4.6
- github.com/nknorg/nkn/v2 v2.2.0
+ github.com/nknorg/nkn-sdk-go v1.4.9-0.20250718092920-5d1593ad7642
+ github.com/nknorg/nkn/v2 v2.2.2-0.20250718093239-1e65fafdf8f0
github.com/nknorg/nkngomobile v0.0.0-20220615081414-671ad1afdfa9
github.com/nknorg/reedsolomon v1.9.12-0.20210315025804-a0c1b6031ab4
+ golang.org/x/mobile v0.0.0-20240905004112-7c4916698cc9
)
require (
@@ -18,16 +20,16 @@ require (
github.com/ethereum/go-ethereum v1.10.15 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
- github.com/golang/protobuf v1.5.3 // indirect
- github.com/google/uuid v1.3.0 // indirect
- github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imdario/mergo v0.3.15 // indirect
- github.com/ipfs/go-cid v0.4.1 // indirect
+ github.com/ipfs/go-cid v0.4.0 // indirect
github.com/itchyny/base58-go v0.2.1 // indirect
github.com/jbenet/go-is-domain v1.0.5 // indirect
- github.com/klauspost/cpuid/v2 v2.2.4 // indirect
+ github.com/jinzhu/copier v0.4.0 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
@@ -35,8 +37,26 @@ require (
github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multihash v0.2.1 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
+ github.com/nknorg/ncp-go v1.0.7-0.20240928081416-1a805ec168d0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
+ github.com/pborman/uuid v1.2.1 // indirect
+ github.com/pion/datachannel v1.5.9 // indirect
+ github.com/pion/dtls/v3 v3.0.2 // indirect
+ github.com/pion/ice/v4 v4.0.1 // indirect
+ github.com/pion/interceptor v0.1.30 // indirect
+ github.com/pion/logging v0.2.2 // indirect
+ github.com/pion/mdns/v2 v2.0.7 // indirect
+ github.com/pion/randutil v0.1.0 // indirect
+ github.com/pion/rtcp v1.2.14 // indirect
+ github.com/pion/rtp v1.8.9 // indirect
+ github.com/pion/sctp v1.8.33 // indirect
+ github.com/pion/sdp/v3 v3.0.9 // indirect
+ github.com/pion/srtp/v3 v3.0.3 // indirect
+ github.com/pion/stun/v3 v3.0.0 // indirect
+ github.com/pion/transport/v3 v3.0.7 // indirect
+ github.com/pion/turn/v4 v4.0.0 // indirect
+ github.com/pion/webrtc/v4 v4.0.0-beta.30 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rjeczalik/notify v0.9.3 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
@@ -45,15 +65,17 @@ require (
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/wealdtech/go-ens/v3 v3.5.4 // indirect
github.com/wealdtech/go-multicodec v1.4.0 // indirect
+ github.com/wlynxg/anet v0.0.4 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
- golang.org/x/crypto v0.7.0 // indirect
- golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c
- golang.org/x/mod v0.8.0 // indirect
- golang.org/x/net v0.8.0 // indirect
- golang.org/x/sys v0.6.0 // indirect
- golang.org/x/text v0.8.0 // indirect
- golang.org/x/tools v0.6.0 // indirect
- google.golang.org/protobuf v1.30.0 // indirect
+ golang.org/x/crypto v0.31.0 // indirect
+ golang.org/x/mod v0.20.0 // indirect
+ golang.org/x/net v0.33.0 // indirect
+ golang.org/x/sync v0.10.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
+ golang.org/x/time v0.6.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)
diff --git a/golib/go.sum b/golib/go.sum
index b084a2460..0d57ddf49 100644
--- a/golib/go.sum
+++ b/golib/go.sum
@@ -166,13 +166,10 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -188,24 +185,27 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
@@ -222,12 +222,13 @@ github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZ
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk=
+github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI=
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
+github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
+github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@@ -243,8 +244,8 @@ github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bS
github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o=
-github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
-github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
+github.com/ipfs/go-cid v0.4.0 h1:a4pdZq0sx6ZSxbCizebnKiMCx/xI/aBBFlB73IgH4rA=
+github.com/ipfs/go-cid v0.4.0/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
github.com/itchyny/base58-go v0.2.1 h1:wtnhAVdOcW3WuHEASmGHMms4juOB8yEpj/KJxlB57+k=
github.com/itchyny/base58-go v0.2.1/go.mod h1:BNvrKeAtWNSca1GohNbyhfff9/v0IrZjzWCAGeAvZZE=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
@@ -255,6 +256,8 @@ github.com/jbenet/go-is-domain v1.0.5/go.mod h1:xbRLRb0S7FgzDBTJlguhDVwLYM/5yNtv
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
+github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
@@ -276,8 +279,8 @@ github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.11/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
-github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
-github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -305,8 +308,9 @@ github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HN
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
-github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
@@ -347,17 +351,17 @@ github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOEL
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
-github.com/nknorg/dns-resolver-go v0.0.0-20220705102626-b041cd8d4a8e h1:GBCXdZ7X3+je1Kz8eq34Y61knTGDkLJqqZEOi87nO7w=
-github.com/nknorg/dns-resolver-go v0.0.0-20220705102626-b041cd8d4a8e/go.mod h1:4kmAlcljv8giDwPUs2SoGNB+KKicismVnOrBy8SgEi8=
+github.com/nknorg/dns-resolver-go v0.0.0-20230404043755-e50d32d9043a h1:aZW6WMDsTZ39bmVNgJq0z5IsQkF3EWrjW6OXmrl03cE=
+github.com/nknorg/dns-resolver-go v0.0.0-20230404043755-e50d32d9043a/go.mod h1:4kmAlcljv8giDwPUs2SoGNB+KKicismVnOrBy8SgEi8=
github.com/nknorg/eth-resolver-go v0.0.0-20230404061427-d0bd773f899f h1:EOCImWeST/oFGiNCjX5ciUHmiQaK+idbCNS0eSojrYk=
github.com/nknorg/eth-resolver-go v0.0.0-20230404061427-d0bd773f899f/go.mod h1:u5Dhckhgl266RlajmjBqvWHt66br0PG5MMg+dunrD1U=
github.com/nknorg/mockconn-go v0.0.0-20230125231524-d664e728352a/go.mod h1:/SvBORYxt9wlm8ZbaEFEri6ooOSDcU3ovU0L2eRRdS4=
-github.com/nknorg/ncp-go v1.0.5 h1:alJjq6bi6tRwUAAv932FIfE/R3S7DRR0pgXOgBXNHAk=
-github.com/nknorg/ncp-go v1.0.5/go.mod h1:ze88qf5e9/DBXSOaJPL2Caa0IbdZJLzESAFM1S7mGwg=
-github.com/nknorg/nkn-sdk-go v1.4.6 h1:GfvOAoC9Lj7WnZrPaO8UC62ieqAeHqNOMrePywsWKQE=
-github.com/nknorg/nkn-sdk-go v1.4.6/go.mod h1:d4+iy0NmckVSgTUHUTloN5X5zcfph86126ubc1Rq9Lg=
-github.com/nknorg/nkn/v2 v2.2.0 h1:sXOawvVF/T3bBTuWbzBCyrGuxldA3be+f+BDjoWcOEA=
-github.com/nknorg/nkn/v2 v2.2.0/go.mod h1:yv3jkg0aOtN9BDHS4yerNSZJtJNBfGvlaD5K6wL6U3E=
+github.com/nknorg/ncp-go v1.0.7-0.20240928081416-1a805ec168d0 h1:x19e5JSW9BpO4glxrOYQnfyoRQEUGQKIkg5XQAV0W1Y=
+github.com/nknorg/ncp-go v1.0.7-0.20240928081416-1a805ec168d0/go.mod h1:y7WJ8zna/EsQ0Hifp8iLFuDRNQfPmDfALapsDfZoHEM=
+github.com/nknorg/nkn-sdk-go v1.4.9-0.20250718092920-5d1593ad7642 h1:9IE50YvWLj8juzBoOt87oG2lKNGFGaq/Ron9P0CfbsQ=
+github.com/nknorg/nkn-sdk-go v1.4.9-0.20250718092920-5d1593ad7642/go.mod h1:CyQJd95NT0UxiF/MDZ3843B5xgKwQCuPdU7wZGRL8Jc=
+github.com/nknorg/nkn/v2 v2.2.2-0.20250718093239-1e65fafdf8f0 h1:y64x9g1QU6jrvLezQ/D6fB8KeHwPqgUa7GYUAgg8jjI=
+github.com/nknorg/nkn/v2 v2.2.2-0.20250718093239-1e65fafdf8f0/go.mod h1:kmV1K5ZNspfubj6KkqfVSw+46uVINUiZ6EWHufg2CwE=
github.com/nknorg/nkngomobile v0.0.0-20220615081414-671ad1afdfa9 h1:Gr37j7Ttvcn8g7TdC5fs6Y6IJKdmfqCvj03UbsrS77o=
github.com/nknorg/nkngomobile v0.0.0-20220615081414-671ad1afdfa9/go.mod h1:zNY9NCyBcJCCDrXhwOjKarkW5cngPs/Z82xVNy/wvEA=
github.com/nknorg/reedsolomon v1.9.12-0.20210315025804-a0c1b6031ab4 h1:Ug3GGTsny4ZcPsDeqOqoiBMts/yA8PBX1TJmMOeyc9Q=
@@ -382,10 +386,44 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
+github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
+github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA=
+github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE=
+github.com/pion/dtls/v3 v3.0.2 h1:425DEeJ/jfuTTghhUDW0GtYZYIwwMtnKKJNMcWccTX0=
+github.com/pion/dtls/v3 v3.0.2/go.mod h1:dfIXcFkKoujDQ+jtd8M6RgqKK3DuaUilm3YatAbGp5k=
+github.com/pion/ice/v4 v4.0.1 h1:2d3tPoTR90F3TcGYeXUwucGlXI3hds96cwv4kjZmb9s=
+github.com/pion/ice/v4 v4.0.1/go.mod h1:2dpakjpd7+74L5j3TAe6gvkbI5UIzOgAnkimm9SuHvA=
+github.com/pion/interceptor v0.1.30 h1:au5rlVHsgmxNi+v/mjOPazbW1SHzfx7/hYOEYQnUcxA=
+github.com/pion/interceptor v0.1.30/go.mod h1:RQuKT5HTdkP2Fi0cuOS5G5WNymTjzXaGF75J4k7z2nc=
+github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
+github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
+github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
+github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
+github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
+github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
+github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
+github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
+github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk=
+github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
+github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw=
+github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM=
+github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
+github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
+github.com/pion/srtp/v3 v3.0.3 h1:tRtEOpmR8NtsB/KndlKXFOj/AIIs6aPrCq4TlAatC4M=
+github.com/pion/srtp/v3 v3.0.3/go.mod h1:Bp9ztzPCoE0ETca/R+bTVTO5kBgaQMiQkTmZWwazDTc=
+github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
+github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
+github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
+github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
+github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
+github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
+github.com/pion/webrtc/v4 v4.0.0-beta.30 h1:ztchBW2RZiiBflmoCIuViD/axDoNkEzoh0CqRWvf6dc=
+github.com/pion/webrtc/v4 v4.0.0-beta.30/go.mod h1:V+nZxyUG8sIUb0uUYQEZzx1PvMPtHlRby4h3xhrjTsg=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -440,6 +478,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -448,8 +487,10 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
@@ -476,6 +517,8 @@ github.com/wealdtech/go-multicodec v1.4.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3h
github.com/wealdtech/go-string2eth v1.1.0 h1:USJQmysUrBYYmZs7d45pMb90hRSyEwizP7lZaOZLDAw=
github.com/wealdtech/go-string2eth v1.1.0/go.mod h1:RUzsLjJtbZaJ/3UKn9kY19a/vCCUHtEWoUW3uiK6yGU=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/wlynxg/anet v0.0.4 h1:0de1OFQxnNqAu+x2FAKKCVIrnfGKQbs7FQz++tB0+Uw=
+github.com/wlynxg/anet v0.0.4/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
@@ -502,8 +545,8 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20220213190939-1e6e3497d506/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
-golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -527,15 +570,15 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c h1:Gk61ECugwEHL6IiyyNLXNzmu8XslmRP2dS0xjIYhbb4=
-golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY=
+golang.org/x/mobile v0.0.0-20240905004112-7c4916698cc9 h1:zWHXwU92JPmIJw5bj6vOZWDZusVxqazOaqhwfUA5l7w=
+golang.org/x/mobile v0.0.0-20240905004112-7c4916698cc9/go.mod h1:udWezQGYjqrCxz5nV321pXQTx5oGbZx+khZvFjZNOPM=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -562,8 +605,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
-golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -578,7 +621,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -624,10 +668,10 @@ golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -639,14 +683,15 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
-golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
+golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -674,12 +719,11 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
@@ -723,12 +767,11 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/golib/gomobile.go b/golib/gomobile.go
index 289b9e6aa..398ff70f9 100644
--- a/golib/gomobile.go
+++ b/golib/gomobile.go
@@ -1,6 +1,8 @@
package nkngolib
import (
+ "nkngolib/search"
+
dnsresolver "github.com/nknorg/dns-resolver-go"
ethresolver "github.com/nknorg/eth-resolver-go"
"github.com/nknorg/nkn-sdk-go"
@@ -16,4 +18,5 @@ var (
_ = nkngomobile.NewStringArray
_ = reedsolomon.New
_ = bind.GenGo
+ _ = search.NewSearchClient
)
diff --git a/golib/search/pow.go b/golib/search/pow.go
new file mode 100644
index 000000000..5fe97f4ad
--- /dev/null
+++ b/golib/search/pow.go
@@ -0,0 +1,392 @@
+package search
+
+import (
+ "bytes"
+ "crypto/ed25519"
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "runtime"
+ "strconv"
+ "sync"
+ "time"
+)
+
+// Challenge represents the PoW challenge structure
+type Challenge struct {
+ Challenges []string `json:"challenges"`
+ Difficulty int `json:"difficulty"`
+ Count int `json:"count"`
+ Hint string `json:"hint"`
+}
+
+// ChallengeResponse represents the API response for challenge request
+type ChallengeResponse struct {
+ Success bool `json:"success"`
+ Data Challenge `json:"data"`
+ Error string `json:"error,omitempty"`
+}
+
+// Solution represents the solution for a single challenge
+type Solution struct {
+ Challenge string `json:"challenge"`
+ Signature string `json:"signature"`
+ Nonce string `json:"nonce"`
+}
+
+// VerifyRequest represents the verification request
+type VerifyRequest struct {
+ PublicKey string `json:"publicKey"`
+ Solutions []Solution `json:"solutions"`
+}
+
+// VerifyResponse represents the verification response
+type VerifyResponse struct {
+ Success bool `json:"success"`
+ Message string `json:"message"`
+ Data struct {
+ PublicKey string `json:"publicKey"`
+ VerifiedAt int64 `json:"verifiedAt"`
+ } `json:"data"`
+ Error string `json:"error,omitempty"`
+}
+
+// PowSolution represents the PoW solution for data submission
+type PowSolution struct {
+ PublicKey string `json:"publicKey"`
+ Solutions []Solution `json:"solutions"`
+}
+
+// SubmitRequest represents the data submission request
+type SubmitRequest struct {
+ PublicKey string `json:"publicKey"`
+ PowSolution PowSolution `json:"powSolution"`
+ NknAddress string `json:"nknAddress"`
+ CustomId string `json:"customId,omitempty"`
+ Nickname string `json:"nickname,omitempty"`
+ PhoneNumber string `json:"phoneNumber,omitempty"`
+}
+
+// SubmitResponse represents the submission response
+type SubmitResponse struct {
+ Success bool `json:"success"`
+ Message string `json:"message"`
+ Error string `json:"error,omitempty"`
+}
+
+// SearchClient is the search client for NKN search server
+type SearchClient struct {
+ apiBase *url.URL
+ privateKey []byte
+ publicKey []byte
+ walletAddr string
+ isVerified bool
+ verifiedUntil time.Time
+ mu sync.RWMutex
+ httpClient *http.Client
+}
+
+// init initializes the search package
+// Sets GOMAXPROCS to enable parallel execution on multi-core devices
+func init() {
+ // Enable parallel execution by setting GOMAXPROCS to CPU count
+ numCPU := runtime.NumCPU()
+ runtime.GOMAXPROCS(numCPU)
+ log.Printf("Search package initialized: GOMAXPROCS set to %d (CPU cores: %d)",
+ runtime.GOMAXPROCS(0), numCPU)
+}
+
+// QueryResult represents the query result
+type QueryResult struct {
+ Success bool `json:"success"`
+ Data string `json:"data"` // JSON formatted result
+ Error string `json:"error,omitempty"`
+}
+
+// sign signs a message (hex string)
+func (c *SearchClient) sign(messageHex string) (string, error) {
+ // NKN SDK expects message to be a hex string, need to decode first
+ messageBytes, err := hex.DecodeString(messageHex)
+ if err != nil {
+ return "", fmt.Errorf("failed to decode hex message: %w", err)
+ }
+
+ // Sign using ed25519
+ signature := ed25519.Sign(c.privateKey, messageBytes)
+
+ // Return hex encoded signature
+ return hex.EncodeToString(signature), nil
+}
+
+// GetPublicKeyHex returns the public key in hex format
+func (c *SearchClient) GetPublicKeyHex() string {
+ return hex.EncodeToString(c.publicKey)
+}
+
+// GetAddress returns the wallet address
+func (c *SearchClient) GetAddress() string {
+ return c.walletAddr
+}
+
+// IsVerified checks if the client is verified
+func (c *SearchClient) IsVerified() bool {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return c.isVerified && time.Now().Before(c.verifiedUntil)
+}
+
+// solvePoW calculates PoW - finds a nonce that satisfies the difficulty
+// Single-threaded optimized version for maximum performance on mobile devices
+func solvePoW(signature string, difficulty int) (string, time.Duration) {
+ startTime := time.Now()
+
+ log.Printf("Starting single-threaded PoW calculation (difficulty: %d)", difficulty)
+
+ // Pre-convert signature to bytes once
+ sigBytes := []byte(signature)
+
+ // Calculate how many leading zero bits we need
+ zeroBits := difficulty * 4 // Each hex digit = 4 bits
+ zeroBytes := zeroBits / 8
+ remainingBits := zeroBits % 8
+
+ // Pre-allocate buffer with enough space
+ buf := make([]byte, len(sigBytes), len(sigBytes)+20)
+ copy(buf, sigBytes)
+
+ nonce := uint64(0)
+
+ // Keep track of where signature ends
+ sigLen := len(sigBytes)
+
+ // Single-threaded tight loop - maximum performance
+ for {
+ // Build data: signature + nonce (optimized - reuse buffer)
+ buf = buf[:sigLen]
+ buf = strconv.AppendUint(buf, nonce, 10)
+
+ // Calculate hash
+ hash := sha256.Sum256(buf)
+
+ // Fast check: compare bytes directly instead of hex string
+ isValid := true
+
+ // Check full zero bytes
+ for k := 0; k < zeroBytes; k++ {
+ if hash[k] != 0 {
+ isValid = false
+ break
+ }
+ }
+
+ // Check remaining bits if needed
+ if isValid && remainingBits > 0 {
+ mask := byte(0xFF << (8 - remainingBits))
+ if (hash[zeroBytes] & mask) != 0 {
+ isValid = false
+ }
+ }
+
+ if isValid {
+ duration := time.Since(startTime)
+ log.Printf("PoW solved: nonce=%d, duration=%v", nonce, duration)
+ return strconv.FormatUint(nonce, 10), duration
+ }
+
+ nonce++
+ }
+}
+
+// getChallenge gets the PoW challenge
+func (c *SearchClient) getChallenge() (*Challenge, error) {
+ url := fmt.Sprintf("%s/auth/challenge?publicKey=%s", c.apiBase, c.GetPublicKeyHex())
+ resp, err := c.httpClient.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ var challengeResp ChallengeResponse
+ if err := json.Unmarshal(body, &challengeResp); err != nil {
+ return nil, err
+ }
+
+ if !challengeResp.Success {
+ return nil, fmt.Errorf("failed to get challenge: %s", challengeResp.Error)
+ }
+
+ return &challengeResp.Data, nil
+}
+
+// getChallengeSubmit gets the PoW challenge for data submission
+func (c *SearchClient) getChallengeSubmit() (*Challenge, error) {
+ url := fmt.Sprintf("%s/auth/challenge-submit?publicKey=%s", c.apiBase, c.GetPublicKeyHex())
+ resp, err := c.httpClient.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ var challengeResp ChallengeResponse
+ if err := json.Unmarshal(body, &challengeResp); err != nil {
+ return nil, err
+ }
+
+ if !challengeResp.Success {
+ return nil, fmt.Errorf("failed to get submit challenge: %s", challengeResp.Error)
+ }
+
+ return &challengeResp.Data, nil
+}
+
+// verify submits PoW solutions for verification
+func (c *SearchClient) verify(solutions []Solution) (*VerifyResponse, error) {
+ url := fmt.Sprintf("%s/auth/verify", c.apiBase)
+
+ reqBody := VerifyRequest{
+ PublicKey: c.GetPublicKeyHex(),
+ Solutions: solutions,
+ }
+
+ jsonData, err := json.Marshal(reqBody)
+ if err != nil {
+ return nil, err
+ }
+
+ resp, err := c.httpClient.Post(url, "application/json", bytes.NewBuffer(jsonData))
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ var verifyResp VerifyResponse
+ if err := json.Unmarshal(body, &verifyResp); err != nil {
+ return nil, err
+ }
+
+ return &verifyResp, nil
+}
+
+// submitData submits user data (requires fresh PoW)
+func (c *SearchClient) submitData(nknAddress, customId, nickname, phoneNumber string) (*SubmitResponse, error) {
+ log.Printf("Starting user data submission...")
+
+ // 1. Get submit challenge
+ challenge, err := c.getChallengeSubmit()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get submit challenge: %w", err)
+ }
+
+ // 2. Solve challenges
+ solutions, err := c.solveChallenges(challenge)
+ if err != nil {
+ return nil, fmt.Errorf("failed to solve challenges: %w", err)
+ }
+
+ // 3. Prepare and submit data
+ url := c.apiBase.JoinPath("data/submit")
+
+ powSolution := PowSolution{
+ PublicKey: c.GetPublicKeyHex(),
+ Solutions: solutions,
+ }
+
+ reqBody := SubmitRequest{
+ PublicKey: c.GetPublicKeyHex(),
+ PowSolution: powSolution,
+ NknAddress: nknAddress,
+ CustomId: customId,
+ Nickname: nickname,
+ PhoneNumber: phoneNumber,
+ }
+
+ jsonData, err := json.Marshal(reqBody)
+ if err != nil {
+ return nil, err
+ }
+
+ log.Printf("Submitting user data to server...")
+ resp, err := c.httpClient.Post(url.String(), "application/json", bytes.NewBuffer(jsonData))
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ // Handle rate limit with detailed message
+ if resp.StatusCode == 429 {
+ log.Printf("⚠️ Rate limit exceeded. Server allows max 10 submits per minute.")
+ log.Printf("Please wait a moment before retrying.")
+ return nil, fmt.Errorf("rate limit exceeded (429): max 10 submits per minute. Please wait and retry")
+ }
+
+ var submitResp SubmitResponse
+ if err := json.Unmarshal(body, &submitResp); err != nil {
+ return nil, err
+ }
+
+ if submitResp.Success {
+ log.Printf("✓ User data submitted successfully: %s", submitResp.Message)
+ } else {
+ log.Printf("✗ User data submission failed: %s", submitResp.Error)
+ }
+
+ return &submitResp, nil
+}
+
+// solveChallenges solves all challenges
+func (c *SearchClient) solveChallenges(challenge *Challenge) ([]Solution, error) {
+ solutions := make([]Solution, 0, len(challenge.Challenges))
+ totalStart := time.Now()
+
+ log.Printf("Starting to solve %d challenges with difficulty %d", len(challenge.Challenges), challenge.Difficulty)
+
+ for i, ch := range challenge.Challenges {
+ // Sign the challenge
+ signature, err := c.sign(ch)
+ if err != nil {
+ return nil, fmt.Errorf("failed to sign challenge: %w", err)
+ }
+
+ // Calculate PoW
+ log.Printf("Solving challenge %d/%d...", i+1, len(challenge.Challenges))
+ nonce, duration := solvePoW(signature, challenge.Difficulty)
+ log.Printf("Challenge %d/%d solved in %v (nonce: %s)", i+1, len(challenge.Challenges), duration, nonce)
+
+ solutions = append(solutions, Solution{
+ Challenge: ch,
+ Signature: signature,
+ Nonce: nonce,
+ })
+ }
+
+ totalDuration := time.Since(totalStart)
+ log.Printf("All challenges solved! Total time: %v (avg: %v per challenge)",
+ totalDuration, totalDuration/time.Duration(len(challenge.Challenges)))
+
+ return solutions, nil
+}
diff --git a/golib/search/search.go b/golib/search/search.go
new file mode 100644
index 000000000..09002804c
--- /dev/null
+++ b/golib/search/search.go
@@ -0,0 +1,285 @@
+package search
+
+import (
+ "crypto/ed25519"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/nknorg/nkn-sdk-go"
+)
+
+// NewSearchClient creates a new search client
+// apiBase: API server address, e.g. "https://search.nkn.org/api/v1"
+// For query-only usage, you can pass empty strings for privateKeyHex, publicKeyHex, and walletAddr
+func NewSearchClient(apiBase string) (*SearchClient, error) {
+ apiBaseURL, err := url.Parse(apiBase)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse API base URL: %w", err)
+ }
+ return &SearchClient{
+ apiBase: apiBaseURL,
+ httpClient: &http.Client{Timeout: 30 * time.Second},
+ }, nil
+}
+
+// NewSearchClientWithAuth creates a new search client with authentication
+// apiBase: API server address, e.g. "https://search.nkn.org/api/v1"
+// seed: NKN seed (hex format, 32 bytes = 64 characters)
+func NewSearchClientWithAuth(apiBase string, seed []byte) (*SearchClient, error) {
+ account, err := nkn.NewAccount(seed)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create account: %w", err)
+ }
+
+ // Decode private key
+ privateKeyBytes := account.PrivateKey
+ if len(privateKeyBytes) != ed25519.PrivateKeySize {
+ return nil, fmt.Errorf("private key must be %d bytes", ed25519.PrivateKeySize)
+ }
+
+ // Decode public key
+ publicKeyBytes := account.PublicKey
+ if len(publicKeyBytes) != ed25519.PublicKeySize {
+ return nil, fmt.Errorf("public key must be %d bytes", ed25519.PublicKeySize)
+ }
+
+ apiBaseURL, err := url.Parse(apiBase)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse API base URL: %w", err)
+ }
+
+ return &SearchClient{
+ apiBase: apiBaseURL,
+ privateKey: privateKeyBytes,
+ publicKey: publicKeyBytes,
+ walletAddr: account.WalletAddress(),
+ httpClient: &http.Client{Timeout: 30 * time.Second},
+ }, nil
+}
+
+// Query queries data by keyword
+// keyword: search keyword
+// Returns JSON formatted query result string, error on failure
+func (c *SearchClient) Query(keyword string) (string, error) {
+ // Build query URL
+ url := c.apiBase.JoinPath("data/query")
+ q := url.Query()
+ q.Set("q", keyword)
+ url.RawQuery = q.Encode()
+
+ // Create request
+ req, err := http.NewRequest("GET", url.String(), nil)
+ if err != nil {
+ return "", err
+ }
+
+ // Send request
+ resp, err := c.httpClient.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("query request failed: %w", err)
+ }
+ defer resp.Body.Close()
+
+ // Read response
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("failed to read response: %w", err)
+ }
+
+ // Return JSON string
+ return string(body), nil
+}
+
+// QueryByID queries data by ID
+// id: ID
+// Returns JSON formatted query result string, error on failure
+func (c *SearchClient) QueryByID(id string) (string, error) {
+ // Build query URL
+ url := c.apiBase.JoinPath("data/query")
+ q := url.Query()
+ q.Set("customId", id)
+ url.RawQuery = q.Encode()
+
+ // Create request
+ req, err := http.NewRequest("GET", url.String(), nil)
+ if err != nil {
+ return "", err
+ }
+
+ // Send request
+ resp, err := c.httpClient.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("query request failed: %w", err)
+ }
+ defer resp.Body.Close()
+
+ // Read response
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("failed to read response: %w", err)
+ }
+
+ // Return JSON string
+ return string(body), nil
+}
+
+// GetMyInfo queries my own information by querying with nknAddress
+// address: NKN address
+// Returns JSON formatted query result string, error on failure
+func (c *SearchClient) GetMyInfo(address string) (string, error) {
+ // Build query URL
+ url := c.apiBase.JoinPath("data/query")
+ q := url.Query()
+ q.Set("nknAddress", address)
+ url.RawQuery = q.Encode()
+
+ log.Printf("[GetMyInfo] Request URL: %s", url.String())
+
+ // Create request
+ req, err := http.NewRequest("GET", url.String(), nil)
+ if err != nil {
+ return "", err
+ }
+
+ // Send request
+ resp, err := c.httpClient.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("query request failed: %w", err)
+ }
+ defer resp.Body.Close()
+
+ log.Printf("[GetMyInfo] Response status: %d %s", resp.StatusCode, resp.Status)
+
+ // Read response
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("failed to read response: %w", err)
+ }
+
+ // Check HTTP status code
+ if resp.StatusCode != http.StatusOK {
+ log.Printf("[GetMyInfo] Error response body: %s", string(body))
+ return "", fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
+ }
+
+ log.Printf("[GetMyInfo] Response body: %s", string(body))
+
+ // Return JSON string
+ return string(body), nil
+}
+
+// SubmitUserData submits or updates user profile data to the search server
+//
+// Parameters:
+// - nknAddress: NKN client address (optional, format: "identifier.publickey" or just publickey)
+// If empty, defaults to publickey. Must be either "identifier.publickey" format or equal to publickey.
+// - customId: Custom identifier (optional, min 3 characters if provided, alphanumeric + underscore only)
+// - nickname: User nickname (optional, can be empty string)
+// - phoneNumber: Phone number (optional, can be empty string)
+//
+// # Returns nil on success, error on failure
+//
+// Important notes:
+// - Each call performs fresh PoW (Proof of Work) automatically - you'll see timing logs
+// - Server rate limit: 10 submits per minute
+// - NO need to call Verify() first - SubmitUserData works independently
+// - Verify() is only useful for query operations (gives 2-hour query access)
+// - If publicKey already exists, will UPDATE the user data (can modify nickname, phoneNumber)
+// - nknAddress validation: must be empty, equal to publickey, or in "identifier.publickey" format
+//
+// Example:
+//
+// // Option 1: Use default (empty - will use publickey)
+// err := client.SubmitUserData("", "", "John Doe", "13800138000")
+//
+// // Option 2: Use publickey directly
+// err := client.SubmitUserData(client.GetPublicKeyHex(), "", "John Doe", "13800138000")
+//
+// // Option 3: Use custom identifier.publickey format
+// err := client.SubmitUserData(
+// "alice." + client.GetPublicKeyHex(), // nknAddress - identifier.publickey
+// "myid123", // customId - optional
+// "John Doe", // nickname - optional
+// "13800138000", // phoneNumber - optional
+// )
+func (c *SearchClient) SubmitUserData(nknAddress, customId, nickname, phoneNumber string) error {
+ // Process nknAddress: if empty, use publicKey
+ finalNknAddress := nknAddress
+ publicKeyHex := c.GetPublicKeyHex()
+
+ if finalNknAddress == "" {
+ finalNknAddress = publicKeyHex
+ } else {
+ // Validate format if contains dot
+ if strings.Contains(finalNknAddress, ".") {
+ parts := strings.Split(finalNknAddress, ".")
+ if len(parts) != 2 {
+ return fmt.Errorf("invalid nknAddress format, expected: identifier.publickey")
+ }
+ providedPubKey := parts[1]
+ if strings.ToLower(providedPubKey) != strings.ToLower(publicKeyHex) {
+ return fmt.Errorf("nknAddress publickey suffix must match your actual publicKey")
+ }
+ } else {
+ // If no dot, must equal publicKey
+ if strings.ToLower(finalNknAddress) != strings.ToLower(publicKeyHex) {
+ return fmt.Errorf("nknAddress must be either \"identifier.publickey\" format or equal to publicKey")
+ }
+ }
+ }
+
+ // Validate customId if provided
+ if customId != "" && len(customId) < 3 {
+ return fmt.Errorf("customId must be at least 3 characters if provided")
+ }
+
+ submitResp, err := c.submitData(finalNknAddress, customId, nickname, phoneNumber)
+ if err != nil {
+ return fmt.Errorf("failed to submit user data: %w", err)
+ }
+
+ if !submitResp.Success {
+ return fmt.Errorf("submit failed: %s", submitResp.Error)
+ }
+
+ return nil
+}
+
+// Verify verifies the public key (completes PoW challenge)
+// Returns nil on success, error on failure
+func (c *SearchClient) Verify() error {
+ // 1. Get challenge
+ challenge, err := c.getChallenge()
+ if err != nil {
+ return fmt.Errorf("failed to get challenge: %w", err)
+ }
+
+ // 2. Solve challenges
+ solutions, err := c.solveChallenges(challenge)
+ if err != nil {
+ return fmt.Errorf("failed to solve challenges: %w", err)
+ }
+
+ // 3. Submit verification
+ verifyResp, err := c.verify(solutions)
+ if err != nil {
+ return fmt.Errorf("failed to verify: %w", err)
+ }
+
+ if !verifyResp.Success {
+ return fmt.Errorf("verification failed: %s", verifyResp.Error)
+ }
+
+ // 4. Update status
+ c.mu.Lock()
+ c.isVerified = true
+ c.verifiedUntil = time.Now().Add(2 * time.Hour) // Valid for 2 hours
+ c.mu.Unlock()
+
+ return nil
+}
diff --git a/ios/.gitignore b/ios/.gitignore
index 151026b91..efa4cb9d3 100644
--- a/ios/.gitignore
+++ b/ios/.gitignore
@@ -31,3 +31,5 @@ Runner/GeneratedPluginRegistrant.*
!default.mode2v3
!default.pbxuser
!default.perspectivev3
+/Flutter/Secrets.xcconfig
+/Runner/Config.generated.swift
diff --git a/ios/Classes/Push2/APNSPusher.swift b/ios/Classes/Push2/APNSPusher.swift
index 3473f8d76..7a3c93522 100644
--- a/ios/Classes/Push2/APNSPusher.swift
+++ b/ios/Classes/Push2/APNSPusher.swift
@@ -1,14 +1,7 @@
-//
-// APNSPusher.swift
-// Runner
-//
-// Created by 蒋治国 on 2021/10/31.
-//
-
import Foundation
-let p12FileName = ""
-let p12FilePasswordd = ""
+let p12FileName = BuildSecrets.apnsP12FileName
+let p12FilePasswordd = BuildSecrets.apnsP12Password
public class APNSPusher {
diff --git a/ios/Classes/impl/SearchService/Search.swift b/ios/Classes/impl/SearchService/Search.swift
new file mode 100644
index 000000000..245e8b291
--- /dev/null
+++ b/ios/Classes/impl/SearchService/Search.swift
@@ -0,0 +1,368 @@
+import Nkn
+
+class SearchService : ChannelBase, FlutterStreamHandler {
+ static var instance: SearchService = SearchService()
+ let searchQueue = DispatchQueue(label: "org.nkn.mobile/native/search/queue", qos: .default, attributes: .concurrent)
+
+ // High priority queue for CPU-intensive PoW calculations
+ // Use userInitiated QoS to ensure maximum CPU resources
+ let powQueue = DispatchQueue(label: "org.nkn.mobile/native/search/pow", qos: .userInitiated, attributes: .concurrent)
+
+ private var searchItem: DispatchWorkItem?
+
+ var methodChannel: FlutterMethodChannel?
+ let METHOD_CHANNEL_NAME = "org.nkn.mobile/native/search"
+ var eventSink: FlutterEventSink?
+
+ // Store search client instances by ID
+ private var clients: [String: SearchSearchClient] = [:]
+ private let clientsLock = NSLock()
+
+ public static func register(controller: FlutterViewController) {
+ instance.install(binaryMessenger: controller as! FlutterBinaryMessenger)
+ }
+
+ func install(binaryMessenger: FlutterBinaryMessenger) {
+ self.methodChannel = FlutterMethodChannel(name: METHOD_CHANNEL_NAME, binaryMessenger: binaryMessenger)
+ self.methodChannel?.setMethodCallHandler(handle)
+ }
+
+ func uninstall() {
+ self.methodChannel?.setMethodCallHandler(nil)
+ }
+
+ func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
+ eventSink = events
+ return nil
+ }
+
+ func onCancel(withArguments arguments: Any?) -> FlutterError? {
+ eventSink = nil
+ return nil
+ }
+
+ private func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ switch call.method {
+ case "newSearchClient":
+ newSearchClient(call, result: result)
+ case "newSearchClientWithAuth":
+ newSearchClientWithAuth(call, result: result)
+ case "query":
+ query(call, result: result)
+ case "submitUserData":
+ submitUserData(call, result: result)
+ case "verify":
+ verify(call, result: result)
+ case "queryByID":
+ queryByID(call, result: result)
+ case "getMyInfo":
+ getMyInfo(call, result: result)
+ case "getPublicKeyHex":
+ getPublicKeyHex(call, result: result)
+ case "getAddress":
+ getAddress(call, result: result)
+ case "isVerified":
+ isVerified(call, result: result)
+ case "disposeClient":
+ disposeClient(call, result: result)
+ default:
+ result(FlutterMethodNotImplemented)
+ }
+ }
+
+ // Create a query-only search client
+ private func newSearchClient(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let apiBase = args["apiBase"] as? String ?? ""
+
+ var error: NSError?
+ guard let client = SearchNewSearchClient(apiBase, &error) else {
+ self.resultError(result: result, error: error, code: "CREATE_CLIENT_FAILED")
+ return
+ }
+
+ // Generate unique ID for this client
+ let clientId = UUID().uuidString
+
+ clientsLock.lock()
+ clients[clientId] = client
+ clientsLock.unlock()
+
+ let response: [String: Any] = [
+ "clientId": clientId
+ ]
+
+ self.resultSuccess(result: result, resp: response)
+ }
+
+ // Create an authenticated search client
+ private func newSearchClientWithAuth(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let apiBase = args["apiBase"] as? String ?? ""
+ guard let seedData = args["seed"] as? FlutterStandardTypedData else {
+ self.resultError(result: result, code: "INVALID_SEED", message: "Seed must be provided")
+ return
+ }
+
+ let seed = seedData.data
+ if seed.count != 32 {
+ self.resultError(result: result, code: "INVALID_SEED", message: "Seed must be exactly 32 bytes")
+ return
+ }
+
+ var error: NSError?
+ guard let client = SearchNewSearchClientWithAuth(apiBase, seed, &error) else {
+ self.resultError(result: result, error: error, code: "CREATE_AUTH_CLIENT_FAILED")
+ return
+ }
+
+ // Generate unique ID for this client
+ let clientId = UUID().uuidString
+
+ clientsLock.lock()
+ clients[clientId] = client
+ clientsLock.unlock()
+
+ let response: [String: Any] = [
+ "clientId": clientId
+ ]
+
+ self.resultSuccess(result: result, resp: response)
+ }
+
+ // Query data by keyword
+ private func query(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+ let keyword = args["keyword"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ searchQueue.async {
+ var error: NSError?
+ let response = client.query(keyword, error: &error)
+
+ if let error = error {
+ self.resultError(result: result, error: error, code: "QUERY_FAILED")
+ return
+ }
+
+ self.resultSuccess(result: result, resp: response)
+ }
+ }
+
+ // Submit user data
+ private func submitUserData(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+ var nknAddress = args["nknAddress"] as? String ?? ""
+ let customId = args["customId"] as? String ?? ""
+ let nickname = args["nickname"] as? String ?? ""
+ let phoneNumber = args["phoneNumber"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ // Use high-priority queue for CPU-intensive PoW calculation
+ let queueItem = DispatchWorkItem {
+ // Process nknAddress: if empty, use publicKey
+ let publicKeyHex = client.getPublicKeyHex()
+
+ if nknAddress.isEmpty {
+ nknAddress = publicKeyHex
+ } else {
+ // Validate format if contains dot
+ if nknAddress.contains(".") {
+ let parts = nknAddress.components(separatedBy: ".")
+ if parts.count != 2 {
+ self.resultError(result: result, code: "INVALID_PARAMETER",
+ message: "Invalid nknAddress format. Expected: identifier.publickey")
+ return
+ }
+ let providedPubKey = parts[1]
+ if providedPubKey.lowercased() != publicKeyHex.lowercased() {
+ self.resultError(result: result, code: "INVALID_PARAMETER",
+ message: "nknAddress publickey suffix must match your actual publicKey")
+ return
+ }
+ } else {
+ // If no dot, must equal publicKey
+ if nknAddress.lowercased() != publicKeyHex.lowercased() {
+ self.resultError(result: result, code: "INVALID_PARAMETER",
+ message: "nknAddress must be either \"identifier.publickey\" format or equal to publicKey")
+ return
+ }
+ }
+ }
+
+ // Validate customId if provided
+ if !customId.isEmpty && customId.count < 3 {
+ self.resultError(result: result, code: "INVALID_PARAMETER",
+ message: "customId must be at least 3 characters if provided")
+ return
+ }
+
+ do {
+ // PoW calculation happens here - runs on high priority background thread
+ try client.submitUserData(nknAddress, customId: customId, nickname: nickname, phoneNumber: phoneNumber)
+ self.resultSuccess(result: result, resp: ["success": true])
+ } catch let error as NSError {
+ self.resultError(result: result, error: error, code: "SUBMIT_FAILED")
+ }
+ }
+ powQueue.async(execute: queueItem)
+ }
+
+ // Verify the client (optional, for query operations)
+ private func verify(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ // Use high-priority queue for CPU-intensive PoW calculation
+ powQueue.async {
+ do {
+ // PoW calculation happens here - runs on high priority background thread
+ try client.verify()
+ self.resultSuccess(result: result, resp: ["success": true])
+ } catch let error as NSError {
+ self.resultError(result: result, error: error, code: "VERIFY_FAILED")
+ }
+ }
+ }
+
+ // Query by ID
+ private func queryByID(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+ let id = args["id"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ searchQueue.async {
+ var error: NSError?
+ let response = client.query(byID: id, error: &error)
+
+ if let error = error {
+ self.resultError(result: result, error: error, code: "QUERY_BY_ID_FAILED")
+ return
+ }
+
+ self.resultSuccess(result: result, resp: response)
+ }
+ }
+
+ // Get my info by nknAddress
+ private func getMyInfo(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+ let address = args["address"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ searchQueue.async {
+ var error: NSError?
+ let response = client.getMyInfo(address, error: &error)
+
+ if let error = error {
+ self.resultError(result: result, error: error, code: "GET_MY_INFO_FAILED")
+ return
+ }
+
+ self.resultSuccess(result: result, resp: response)
+ }
+ }
+
+ // Get public key hex
+ private func getPublicKeyHex(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ let publicKeyHex = client.getPublicKeyHex()
+ self.resultSuccess(result: result, resp: publicKeyHex)
+ }
+
+ // Get wallet address
+ private func getAddress(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ let address = client.getAddress()
+ self.resultSuccess(result: result, resp: address)
+ }
+
+ // Check if verified
+ private func isVerified(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+
+ clientsLock.lock()
+ guard let client = clients[clientId] else {
+ clientsLock.unlock()
+ self.resultError(result: result, code: "CLIENT_NOT_FOUND", message: "Search client not found")
+ return
+ }
+ clientsLock.unlock()
+
+ let verified = client.isVerified()
+ self.resultSuccess(result: result, resp: verified)
+ }
+
+ // Dispose client
+ private func disposeClient(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ let args = call.arguments as? [String: Any] ?? [String: Any]()
+ let clientId = args["clientId"] as? String ?? ""
+
+ clientsLock.lock()
+ clients.removeValue(forKey: clientId)
+ clientsLock.unlock()
+
+ self.resultSuccess(result: result, resp: ["success": true])
+ }
+}
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 7c5696400..391a902b2 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -20,7 +20,5 @@
????
CFBundleVersion
1.0
- MinimumOSVersion
- 12.0
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
index ec97fc6f3..d70aca916 100644
--- a/ios/Flutter/Debug.xcconfig
+++ b/ios/Flutter/Debug.xcconfig
@@ -1,2 +1,3 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
+#include? "Secrets.xcconfig"
\ No newline at end of file
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
index c4855bfe2..6f461927f 100644
--- a/ios/Flutter/Release.xcconfig
+++ b/ios/Flutter/Release.xcconfig
@@ -1,2 +1,3 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
+#include? "Secrets.xcconfig"
\ No newline at end of file
diff --git a/ios/Podfile b/ios/Podfile
index fe5bdacf5..6d741768e 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
-platform :ios, '12.0'
+platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@@ -32,12 +32,15 @@ target 'Runner' do
use_modular_headers!
#pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '8.4.0'
-
+ pod 'Firebase/Analytics'
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
- target 'Share Extension' do
- inherit! :search_paths
+ # share_handler addition start
+ target 'ShareExtension' do
+ inherit! :search_paths
+ pod "share_handler_ios_models", :path => ".symlinks/plugins/share_handler_ios/ios/Models"
end
+ # share_handler addition end
end
post_install do |installer|
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 174a5617e..13abb572c 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -36,9 +36,47 @@ PODS:
- DKPhotoGallery/Resource (0.0.19):
- SDWebImage
- SwiftyGif
+ - emoji_picker_flutter (0.0.1):
+ - Flutter
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
+ - Firebase/Analytics (11.15.0):
+ - Firebase/Core
+ - Firebase/Core (11.15.0):
+ - Firebase/CoreOnly
+ - FirebaseAnalytics (~> 11.15.0)
+ - Firebase/CoreOnly (11.15.0):
+ - FirebaseCore (~> 11.15.0)
+ - FirebaseAnalytics (11.15.0):
+ - FirebaseAnalytics/Default (= 11.15.0)
+ - FirebaseCore (~> 11.15.0)
+ - FirebaseInstallations (~> 11.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - FirebaseAnalytics/Default (11.15.0):
+ - FirebaseCore (~> 11.15.0)
+ - FirebaseInstallations (~> 11.0)
+ - GoogleAppMeasurement/Default (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - FirebaseCore (11.15.0):
+ - FirebaseCoreInternal (~> 11.15.0)
+ - GoogleUtilities/Environment (~> 8.1)
+ - GoogleUtilities/Logger (~> 8.1)
+ - FirebaseCoreInternal (11.15.0):
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - FirebaseInstallations (11.15.0):
+ - FirebaseCore (~> 11.15.0)
+ - GoogleUtilities/Environment (~> 8.1)
+ - GoogleUtilities/UserDefaults (~> 8.1)
+ - PromisesObjC (~> 2.4)
- Flutter (1.0.0)
- flutter_image_compress_common (1.0.0):
- Flutter
@@ -55,12 +93,67 @@ PODS:
- Flutter
- flutter_sound_core (= 9.28.0)
- flutter_sound_core (9.28.0)
- - FMDB/SQLCipher (2.7.11):
- - SQLCipher (~> 4.0)
+ - FMDB/Core (2.7.12)
+ - FMDB/SQLCipher (2.7.12):
+ - FMDB/Core
+ - SQLCipher (~> 4.6)
+ - GoogleAdsOnDeviceConversion (2.1.0):
+ - GoogleUtilities/Logger (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - nanopb (~> 3.30910.0)
+ - GoogleAppMeasurement/Core (11.15.0):
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - GoogleAppMeasurement/Default (11.15.0):
+ - GoogleAdsOnDeviceConversion (= 2.1.0)
+ - GoogleAppMeasurement/Core (= 11.15.0)
+ - GoogleAppMeasurement/IdentitySupport (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - GoogleAppMeasurement/IdentitySupport (11.15.0):
+ - GoogleAppMeasurement/Core (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - GoogleUtilities/AppDelegateSwizzler (8.1.0):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Network
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Environment (8.1.0):
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Logger (8.1.0):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/MethodSwizzler (8.1.0):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Network (8.1.0):
+ - GoogleUtilities/Logger
+ - "GoogleUtilities/NSData+zlib"
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Reachability
+ - "GoogleUtilities/NSData+zlib (8.1.0)":
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Privacy (8.1.0)
+ - GoogleUtilities/Reachability (8.1.0):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/UserDefaults (8.1.0):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
- image_cropper (0.0.4):
- Flutter
- TOCropViewController (~> 2.7.4)
- - image_gallery_saver (2.0.2):
+ - image_gallery_saver_plus (0.0.1):
- Flutter
- image_picker_ios (0.0.1):
- Flutter
@@ -83,6 +176,11 @@ PODS:
- Mantle/extobjc (= 2.2.0)
- Mantle/extobjc (2.2.0)
- MTBBarcodeScanner (5.0.11)
+ - nanopb (3.30910.0):
+ - nanopb/decode (= 3.30910.0)
+ - nanopb/encode (= 3.30910.0)
+ - nanopb/decode (3.30910.0)
+ - nanopb/encode (3.30910.0)
- nkn_sdk_flutter (0.1.15):
- Flutter
- open_filex (0.0.2):
@@ -94,15 +192,14 @@ PODS:
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
+ - PromisesObjC (2.4.0)
- qr_code_scanner (0.2.0):
- Flutter
- MTBBarcodeScanner
- - receive_sharing_intent (1.8.1):
- - Flutter
- - SDWebImage (5.21.0):
- - SDWebImage/Core (= 5.21.0)
- - SDWebImage/Core (5.21.0)
- - SDWebImageWebPCoder (0.14.6):
+ - SDWebImage (5.21.5):
+ - SDWebImage/Core (= 5.21.5)
+ - SDWebImage/Core (5.21.5)
+ - SDWebImageWebPCoder (0.15.0):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
- Sentry/HybridSDK (8.46.0)
@@ -110,24 +207,30 @@ PODS:
- Flutter
- FlutterMacOS
- Sentry/HybridSDK (= 8.46.0)
+ - share_handler_ios (0.0.14):
+ - Flutter
+ - share_handler_ios/share_handler_ios_models (= 0.0.14)
+ - share_handler_ios_models
+ - share_handler_ios/share_handler_ios_models (0.0.14):
+ - Flutter
+ - share_handler_ios_models
+ - share_handler_ios_models (0.0.9)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- - sqflite (0.0.2):
- - Flutter
- - FMDB/SQLCipher (>= 2.7.5)
- - SQLCipher (~> 4.5.0)
- sqflite_sqlcipher (0.0.1):
- Flutter
- FMDB/SQLCipher (~> 2.7.5)
- - SQLCipher (= 4.5.4)
- - SQLCipher (4.5.4):
- - SQLCipher/standard (= 4.5.4)
- - SQLCipher/common (4.5.4)
- - SQLCipher/standard (4.5.4):
+ - SQLCipher (= 4.10.0)
+ - SQLCipher (4.10.0):
+ - SQLCipher/standard (= 4.10.0)
+ - SQLCipher/common (4.10.0)
+ - SQLCipher/standard (4.10.0):
- SQLCipher/common
+ - store_checker (0.0.1):
+ - Flutter
- SwiftyGif (5.4.5)
- TOCropViewController (2.7.4)
- url_launcher_ios (0.0.1):
@@ -148,7 +251,9 @@ DEPENDENCIES:
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
+ - emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
+ - Firebase/Analytics
- Flutter (from `Flutter`)
- flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
@@ -156,7 +261,7 @@ DEPENDENCIES:
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- flutter_sound (from `.symlinks/plugins/flutter_sound/ios`)
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
- - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
+ - image_gallery_saver_plus (from `.symlinks/plugins/image_gallery_saver_plus/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
- nkn_sdk_flutter (from `.symlinks/plugins/nkn_sdk_flutter/ios`)
@@ -165,12 +270,13 @@ DEPENDENCIES:
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- - receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
+ - share_handler_ios (from `.symlinks/plugins/share_handler_ios/ios`)
+ - share_handler_ios_models (from `.symlinks/plugins/share_handler_ios/ios/Models`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- - sqflite (from `.symlinks/plugins/sqflite/ios`)
- sqflite_sqlcipher (from `.symlinks/plugins/sqflite_sqlcipher/ios`)
+ - store_checker (from `.symlinks/plugins/store_checker/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- vibration (from `.symlinks/plugins/vibration/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
@@ -181,11 +287,21 @@ SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
+ - Firebase
+ - FirebaseAnalytics
+ - FirebaseCore
+ - FirebaseCoreInternal
+ - FirebaseInstallations
- flutter_sound_core
- FMDB
+ - GoogleAdsOnDeviceConversion
+ - GoogleAppMeasurement
+ - GoogleUtilities
- libwebp
- Mantle
- MTBBarcodeScanner
+ - nanopb
+ - PromisesObjC
- SDWebImage
- SDWebImageWebPCoder
- Sentry
@@ -200,6 +316,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/connectivity_plus/ios"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
+ emoji_picker_flutter:
+ :path: ".symlinks/plugins/emoji_picker_flutter/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
@@ -216,8 +334,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_sound/ios"
image_cropper:
:path: ".symlinks/plugins/image_cropper/ios"
- image_gallery_saver:
- :path: ".symlinks/plugins/image_gallery_saver/ios"
+ image_gallery_saver_plus:
+ :path: ".symlinks/plugins/image_gallery_saver_plus/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
local_auth_darwin:
@@ -234,18 +352,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/permission_handler_apple/ios"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
- receive_sharing_intent:
- :path: ".symlinks/plugins/receive_sharing_intent/ios"
sentry_flutter:
:path: ".symlinks/plugins/sentry_flutter/ios"
+ share_handler_ios:
+ :path: ".symlinks/plugins/share_handler_ios/ios"
+ share_handler_ios_models:
+ :path: ".symlinks/plugins/share_handler_ios/ios/Models"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
- sqflite:
- :path: ".symlinks/plugins/sqflite/ios"
sqflite_sqlcipher:
:path: ".symlinks/plugins/sqflite_sqlcipher/ios"
+ store_checker:
+ :path: ".symlinks/plugins/store_checker/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
vibration:
@@ -258,51 +378,63 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS:
- audio_session: 19e9480dbdd4e5f6c4543826b2e8b0e4ab6145fe
- connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
- device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
+ audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
+ connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
+ device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
- file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
- Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
- flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e
- flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9
- flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
- flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
- flutter_sound: 82aba29055d6feba684d08906e0623217b87bcd3
+ emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc
+ file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
+ Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
+ FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae
+ FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e
+ FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4
+ FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
+ Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
+ flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
+ flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4
+ flutter_native_splash: 9e672d3818957718ee006a491730c09deeecace9
+ flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
+ flutter_sound: b9236a5875299aaa4cef1690afd2f01d52a3f890
flutter_sound_core: 427465f72d07ab8c3edbe8ffdde709ddacd3763c
- FMDB: 57486c1117fd8e0e6b947b2f54c3f42bf8e57a4e
- image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
- image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
- image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
+ FMDB: 728731dd336af3936ce00f91d9d8495f5718a0e6
+ GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64
+ GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539
+ GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
+ image_cropper: 5f162dcf988100dc1513f9c6b7eb42cd6fbf9156
+ image_gallery_saver_plus: e597bf65a7846979417a3eae0763b71b6dfec6c3
+ image_picker_ios: afb77645f1e1060a27edb6793996ff9b42256909
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
- local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
+ local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
- nkn_sdk_flutter: cb83324eb3ef17419f715707b59bee20a9adfd34
- open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
- package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
- path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
- permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
- qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
- receive_sharing_intent: 79c848f5b045674ad60b9fea3bafea59962ad2c1
- SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
- SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
+ nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
+ nkn_sdk_flutter: 5f3fb21d48cd76f5d7be35851b9b03b1a18080e2
+ open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1
+ package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
+ path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
+ permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
+ PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
+ qr_code_scanner: d77f94ecc9abf96d9b9b8fc04ef13f611e5a147a
+ SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
+ SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
- sentry_flutter: 2df8b0aab7e4aba81261c230cbea31c82a62dd1b
- share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
- shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
- sqflite: a34731c4ca238cea2ed4869aae5d17559bee4c9f
- sqflite_sqlcipher: 2f7e72fbda46fe3255493ba3f21ebe232ff9a243
- SQLCipher: 905b145f65f349f26da9e60a19901ad24adcd381
+ sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684
+ share_handler_ios: e2244e990f826b2c8eaa291ac3831569438ba0fb
+ share_handler_ios_models: fc638c9b4330dc7f082586c92aee9dfa0b87b871
+ share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
+ shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
+ sqflite_sqlcipher: 8e5bdaae6b2c254f8a277a564f07bc4e2a8642a3
+ SQLCipher: eb79c64049cb002b4e9fcb30edb7979bf4706dfc
+ store_checker: bcaa4c645cbb578f7f087cd6088d42ba26135470
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
- url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
- vibration: 3797858f8cbf53d841e189ef8bd533d96e4ca93c
- video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
- video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1
- webview_flutter_wkwebview: a4af96a051138e28e29f60101d094683b9f82188
+ url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
+ vibration: 69774ad57825b11c951ee4c46155f455d7a592ce
+ video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
+ video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140
+ webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2
-PODFILE CHECKSUM: a8cf2dfbe1b071139a60232df9500666d3de11f4
+PODFILE CHECKSUM: ccfab3afb7c1569fe4d39ff1e877dd45b28d84c6
COCOAPODS: 1.16.2
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 06bee2602..2f447dd3f 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -3,17 +3,20 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 54;
+ objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
+ 147F890F2E83CBC000BFD48B /* ShareExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 147F89052E83CBC000BFD48B /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ 147F899F2EA0F29300BFD48B /* Config.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147F899E2EA0F29300BFD48B /* Config.generated.swift */; };
+ 147F89C22EAB685B00BFD48B /* Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147F89C12EAB684F00BFD48B /* Search.swift */; };
+ 148FFB1A2E60499C005410D0 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 148FFB192E60499C005410D0 /* GoogleService-Info.plist */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
149BC80728FEAEB000D27A6D /* DnsResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149BC80628FEAEB000D27A6D /* DnsResolver.swift */; };
14A871CE287D6DB00093692A /* EthResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A871CD287D6DAF0093692A /* EthResolver.swift */; };
- 14CD34D62D4F43B300789E6D /* Share Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 14CD34CC2D4F43B300789E6D /* Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
- 26F296F8EDE0173FA7F16398 /* Pods_Share_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 91E30255B5E624B5EF52D2D5 /* Pods_Share_Extension.framework */; };
+ 2965BED301999E2B8AAC496C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 334D81B7E27D6131B561C943 /* Pods_Runner.framework */; };
+ 38534CB55C06EB49E66DECD2 /* Pods_ShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CB8FE12826229F00614A342 /* Pods_ShareExtension.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
- 405621D90C76768D15AE18AC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AEEB1EA9E73BDE1EEC27FDA /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@@ -43,12 +46,12 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 14CD34D42D4F43B300789E6D /* PBXContainerItemProxy */ = {
+ 147F890D2E83CBC000BFD48B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 14CD34CB2D4F43B300789E6D;
- remoteInfo = "Share Extension";
+ remoteGlobalIDString = 147F89042E83CBC000BFD48B;
+ remoteInfo = ShareExtension;
};
/* End PBXContainerItemProxy section */
@@ -65,11 +68,11 @@
};
E1B3F2B6291BA8040042F7B2 /* Embed App Extensions */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
+ buildActionMask = 12;
dstPath = "";
dstSubfolderSpec = 13;
files = (
- 14CD34D62D4F43B300789E6D /* Share Extension.appex in Embed App Extensions */,
+ 147F890F2E83CBC000BFD48B /* ShareExtension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
@@ -77,23 +80,30 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 00DDD0F3B83E3CC2A5212805 /* Pods-Share Extension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.profile.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.profile.xcconfig"; sourceTree = ""; };
- 0AEEB1EA9E73BDE1EEC27FDA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 02EED84DF132B94A356E3DA4 /* Pods-Share Extension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.profile.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.profile.xcconfig"; sourceTree = ""; };
+ 0C98E54980A890E1BD057FA6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ 142209AC2E7AB14500C679DC /* receive_sharing_intent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = receive_sharing_intent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 147F89052E83CBC000BFD48B /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ 147F899E2EA0F29300BFD48B /* Config.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.generated.swift; sourceTree = ""; };
+ 147F89C12EAB684F00BFD48B /* Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Search.swift; sourceTree = ""; };
+ 147F8A132EAF5B4000BFD48B /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
+ 147F8A252EAF5BE400BFD48B /* libresolv.9.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.9.tbd; path = usr/lib/libresolv.9.tbd; sourceTree = SDKROOT; };
+ 148FFB192E60499C005410D0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
149BC80628FEAEB000D27A6D /* DnsResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DnsResolver.swift; sourceTree = ""; };
14A871CD287D6DAF0093692A /* EthResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthResolver.swift; sourceTree = ""; };
- 14CD34CC2D4F43B300789E6D /* Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
- 2B0A2868D4D098A65BBC45F1 /* Pods_Sharing_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sharing_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 2F1390E9C951F8699CC4CC1B /* Pods-Share Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.release.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.release.xcconfig"; sourceTree = ""; };
- 351D750FD58E06401D12F03A /* Pods-Sharing Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sharing Extension.release.xcconfig"; path = "Target Support Files/Pods-Sharing Extension/Pods-Sharing Extension.release.xcconfig"; sourceTree = ""; };
+ 2BD846195C7A4EF53B2AAABB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
+ 334D81B7E27D6131B561C943 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
- 3D26C5798BF716A04D05B747 /* Pods-Sharing Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sharing Extension.debug.xcconfig"; path = "Target Support Files/Pods-Sharing Extension/Pods-Sharing Extension.debug.xcconfig"; sourceTree = ""; };
- 5C3F370BC1B3BB2B5BE7210C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ 3C6D0BD6B5E0E014F40856BD /* Pods-ShareExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.profile.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.profile.xcconfig"; sourceTree = ""; };
+ 584544DF38FA171ACDCA775B /* Pods-ShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.debug.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.debug.xcconfig"; sourceTree = ""; };
+ 6CB8FE12826229F00614A342 /* Pods_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
- 91E30255B5E624B5EF52D2D5 /* Pods_Share_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Share_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7F6144DC7E3F6B8544F0EE4F /* Pods-ShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.release.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.release.xcconfig"; sourceTree = ""; };
+ 8AF95113A5629FC499DAE55F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -101,9 +111,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- A5F39BA325F55CCD6883EEB7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
- C210A1A73EDB772675FF4A58 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
- C5AB1F67FA58708668EABC72 /* Pods-Sharing Extension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sharing Extension.profile.xcconfig"; path = "Target Support Files/Pods-Sharing Extension/Pods-Sharing Extension.profile.xcconfig"; sourceTree = ""; };
+ 9C257DECA1497057748992AF /* Pods_Share_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Share_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ BD68F6F0F500A9479AA449AA /* Pods-Share Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.release.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.release.xcconfig"; sourceTree = ""; };
C61A6E6F266A1A7C00A7F1E1 /* Common.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = ""; };
C62BB8042689AA0D00DAAC43 /* NWSSLConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NWSSLConnection.h; sourceTree = ""; };
C62BB8052689AA0D00DAAC43 /* NWSecTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NWSecTools.h; sourceTree = ""; };
@@ -137,36 +146,36 @@
C6FFD762266E09E600410547 /* CommonOc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommonOc.h; sourceTree = ""; };
C6FFD763266E09E600410547 /* CommonOc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CommonOc.m; sourceTree = ""; };
E1852ED72878179100FC45FD /* Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = ""; };
- FF85B414D2042FADD297DB3E /* Pods-Share Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.debug.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.debug.xcconfig"; sourceTree = ""; };
+ EA4800B8A7D823487FC27079 /* Pods-Share Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.debug.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.debug.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
- 14CD34D72D4F43B300789E6D /* Exceptions for "Share Extension" folder in "Share Extension" target */ = {
+ 147F89132E83CBC000BFD48B /* Exceptions for "ShareExtension" folder in "ShareExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
- target = 14CD34CB2D4F43B300789E6D /* Share Extension */;
+ target = 147F89042E83CBC000BFD48B /* ShareExtension */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
- 14CD34CD2D4F43B300789E6D /* Share Extension */ = {
+ 147F89062E83CBC000BFD48B /* ShareExtension */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
- 14CD34D72D4F43B300789E6D /* Exceptions for "Share Extension" folder in "Share Extension" target */,
+ 147F89132E83CBC000BFD48B /* Exceptions for "ShareExtension" folder in "ShareExtension" target */,
);
- path = "Share Extension";
+ path = ShareExtension;
sourceTree = "";
};
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
- 14CD34C92D4F43B300789E6D /* Frameworks */ = {
+ 147F89022E83CBC000BFD48B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 26F296F8EDE0173FA7F16398 /* Pods_Share_Extension.framework in Frameworks */,
+ 38534CB55C06EB49E66DECD2 /* Pods_ShareExtension.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -174,16 +183,25 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 405621D90C76768D15AE18AC /* Pods_Runner.framework in Frameworks */,
+ 2965BED301999E2B8AAC496C /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 147F89C02EAB684700BFD48B /* SearchService */ = {
+ isa = PBXGroup;
+ children = (
+ 147F89C12EAB684F00BFD48B /* Search.swift */,
+ );
+ path = SearchService;
+ sourceTree = "";
+ };
149BC80528FD5E9300D27A6D /* impl */ = {
isa = PBXGroup;
children = (
+ 147F89C02EAB684700BFD48B /* SearchService */,
14A871CC287D6D980093692A /* NameService */,
);
path = impl;
@@ -201,25 +219,28 @@
3D6E1C9BD273F4DA4DBFC297 /* Pods */ = {
isa = PBXGroup;
children = (
- 5C3F370BC1B3BB2B5BE7210C /* Pods-Runner.debug.xcconfig */,
- A5F39BA325F55CCD6883EEB7 /* Pods-Runner.release.xcconfig */,
- C210A1A73EDB772675FF4A58 /* Pods-Runner.profile.xcconfig */,
- 3D26C5798BF716A04D05B747 /* Pods-Sharing Extension.debug.xcconfig */,
- 351D750FD58E06401D12F03A /* Pods-Sharing Extension.release.xcconfig */,
- C5AB1F67FA58708668EABC72 /* Pods-Sharing Extension.profile.xcconfig */,
- FF85B414D2042FADD297DB3E /* Pods-Share Extension.debug.xcconfig */,
- 2F1390E9C951F8699CC4CC1B /* Pods-Share Extension.release.xcconfig */,
- 00DDD0F3B83E3CC2A5212805 /* Pods-Share Extension.profile.xcconfig */,
+ 0C98E54980A890E1BD057FA6 /* Pods-Runner.debug.xcconfig */,
+ 8AF95113A5629FC499DAE55F /* Pods-Runner.release.xcconfig */,
+ 2BD846195C7A4EF53B2AAABB /* Pods-Runner.profile.xcconfig */,
+ EA4800B8A7D823487FC27079 /* Pods-Share Extension.debug.xcconfig */,
+ BD68F6F0F500A9479AA449AA /* Pods-Share Extension.release.xcconfig */,
+ 02EED84DF132B94A356E3DA4 /* Pods-Share Extension.profile.xcconfig */,
+ 584544DF38FA171ACDCA775B /* Pods-ShareExtension.debug.xcconfig */,
+ 7F6144DC7E3F6B8544F0EE4F /* Pods-ShareExtension.release.xcconfig */,
+ 3C6D0BD6B5E0E014F40856BD /* Pods-ShareExtension.profile.xcconfig */,
);
path = Pods;
sourceTree = "";
};
- 6D8B405AB30FE86D2746B39D /* Frameworks */ = {
+ 594E66BF7E7D2CAB5FC62094 /* Frameworks */ = {
isa = PBXGroup;
children = (
- 0AEEB1EA9E73BDE1EEC27FDA /* Pods_Runner.framework */,
- 2B0A2868D4D098A65BBC45F1 /* Pods_Sharing_Extension.framework */,
- 91E30255B5E624B5EF52D2D5 /* Pods_Share_Extension.framework */,
+ 147F8A252EAF5BE400BFD48B /* libresolv.9.tbd */,
+ 147F8A132EAF5B4000BFD48B /* libresolv.tbd */,
+ 142209AC2E7AB14500C679DC /* receive_sharing_intent.framework */,
+ 334D81B7E27D6131B561C943 /* Pods_Runner.framework */,
+ 9C257DECA1497057748992AF /* Pods_Share_Extension.framework */,
+ 6CB8FE12826229F00614A342 /* Pods_ShareExtension.framework */,
);
name = Frameworks;
sourceTree = "";
@@ -241,10 +262,10 @@
C61A6E6D266A19F000A7F1E1 /* Classes */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
- 14CD34CD2D4F43B300789E6D /* Share Extension */,
+ 147F89062E83CBC000BFD48B /* ShareExtension */,
97C146EF1CF9000F007C117D /* Products */,
3D6E1C9BD273F4DA4DBFC297 /* Pods */,
- 6D8B405AB30FE86D2746B39D /* Frameworks */,
+ 594E66BF7E7D2CAB5FC62094 /* Frameworks */,
);
sourceTree = "";
};
@@ -252,7 +273,7 @@
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
- 14CD34CC2D4F43B300789E6D /* Share Extension.appex */,
+ 147F89052E83CBC000BFD48B /* ShareExtension.appex */,
);
name = Products;
sourceTree = "";
@@ -260,6 +281,8 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
+ 147F899E2EA0F29300BFD48B /* Config.generated.swift */,
+ 148FFB192E60499C005410D0 /* GoogleService-Info.plist */,
C6CABF45268452450054F007 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
@@ -348,46 +371,47 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
- 14CD34CB2D4F43B300789E6D /* Share Extension */ = {
+ 147F89042E83CBC000BFD48B /* ShareExtension */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 14CD34D82D4F43B300789E6D /* Build configuration list for PBXNativeTarget "Share Extension" */;
+ buildConfigurationList = 147F89142E83CBC000BFD48B /* Build configuration list for PBXNativeTarget "ShareExtension" */;
buildPhases = (
- BCFE6FCF12ECC9CC408AED6A /* [CP] Check Pods Manifest.lock */,
- 14CD34C82D4F43B300789E6D /* Sources */,
- 14CD34C92D4F43B300789E6D /* Frameworks */,
- 14CD34CA2D4F43B300789E6D /* Resources */,
+ F9E650D65F4A45AFD5FC8C65 /* [CP] Check Pods Manifest.lock */,
+ 147F89012E83CBC000BFD48B /* Sources */,
+ 147F89022E83CBC000BFD48B /* Frameworks */,
+ 147F89032E83CBC000BFD48B /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
- 14CD34CD2D4F43B300789E6D /* Share Extension */,
+ 147F89062E83CBC000BFD48B /* ShareExtension */,
);
- name = "Share Extension";
- productName = "Share Extension";
- productReference = 14CD34CC2D4F43B300789E6D /* Share Extension.appex */;
+ name = ShareExtension;
+ productName = ShareExtension;
+ productReference = 147F89052E83CBC000BFD48B /* ShareExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
- 31910CF38E8EA38D5B7FA35B /* [CP] Check Pods Manifest.lock */,
+ 4D8F8F659CC99985592659DA /* [CP] Check Pods Manifest.lock */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
E1B3F2B6291BA8040042F7B2 /* Embed App Extensions */,
- 12D1C02525059AFAAE4402B0 /* [CP] Embed Pods Frameworks */,
9740EEB61CF901F6004384FC /* Run Script */,
+ 147F899D2EA0F0C900BFD48B /* ShellScript */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
- 60A233074E1A78C397C3A119 /* [CP] Copy Pods Resources */,
+ 9992624A3087AEB0CE096628 /* [CP] Embed Pods Frameworks */,
+ 7F5ECBC81637C095A2530E83 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
- 14CD34D52D4F43B300789E6D /* PBXTargetDependency */,
+ 147F890E2E83CBC000BFD48B /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
@@ -400,12 +424,12 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastSwiftUpdateCheck = 1620;
+ LastSwiftUpdateCheck = 2600;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
- 14CD34CB2D4F43B300789E6D = {
- CreatedOnToolsVersion = 16.2;
+ 147F89042E83CBC000BFD48B = {
+ CreatedOnToolsVersion = 26.0.1;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
@@ -427,13 +451,13 @@
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
- 14CD34CB2D4F43B300789E6D /* Share Extension */,
+ 147F89042E83CBC000BFD48B /* ShareExtension */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
- 14CD34CA2D4F43B300789E6D /* Resources */ = {
+ 147F89032E83CBC000BFD48B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -451,68 +475,69 @@
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
C62BB8282689B1CA00DAAC43 /* nkn.p12 in Resources */,
+ 148FFB1A2E60499C005410D0 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 12D1C02525059AFAAE4402B0 /* [CP] Embed Pods Frameworks */ = {
+ 147F899D2EA0F0C900BFD48B /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
- name = "[CP] Embed Pods Frameworks";
+ inputPaths = (
+ );
outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
- showEnvVarsInLog = 0;
+ shellScript = "set -euo pipefail\n\nOUT_FILE=\"$SRCROOT/Runner/Config.generated.swift\"\n\n# 这些值来自 .xcconfig(或 Scheme/CI 环境变量)\n: \"${P12_FILE_NAME:=}\"\n: \"${P12_FILE_PASSWORD:=}\"\n\ncat > \"$OUT_FILE\" < /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- showEnvVarsInLog = 0;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
};
- 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ 4D8F8F659CC99985592659DA /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
- alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
+ inputFileListPaths = (
+ );
inputPaths = (
- "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
);
- name = "Thin Binary";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
};
- 60A233074E1A78C397C3A119 /* [CP] Copy Pods Resources */ = {
+ 7F5ECBC81637C095A2530E83 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -520,10 +545,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
@@ -544,7 +573,28 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
- BCFE6FCF12ECC9CC408AED6A /* [CP] Check Pods Manifest.lock */ = {
+ 9992624A3087AEB0CE096628 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ F9E650D65F4A45AFD5FC8C65 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -559,7 +609,7 @@
outputFileListPaths = (
);
outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Share Extension-checkManifestLockResult.txt",
+ "$(DERIVED_FILE_DIR)/Pods-ShareExtension-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -569,7 +619,7 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
- 14CD34C82D4F43B300789E6D /* Sources */ = {
+ 147F89012E83CBC000BFD48B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -584,6 +634,7 @@
C6FFD764266E09E600410547 /* CommonOc.m in Sources */,
C62BB8192689AA0E00DAAC43 /* NWSSLConnection.m in Sources */,
C6824D2E272E4EA900BA7AAF /* APNsPort.swift in Sources */,
+ 147F899F2EA0F29300BFD48B /* Config.generated.swift in Sources */,
C62BB8182689AA0E00DAAC43 /* NWType.m in Sources */,
C6824D2B272E4EA900BA7AAF /* PKCS12Adapter.swift in Sources */,
E1852ED82878179100FC45FD /* Crypto.swift in Sources */,
@@ -601,6 +652,7 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
C62BB8162689AA0E00DAAC43 /* NWPushFeedback.m in Sources */,
C62BB81A2689AA0E00DAAC43 /* NWPusher.m in Sources */,
+ 147F89C22EAB685B00BFD48B /* Search.swift in Sources */,
C6824D29272E4EA900BA7AAF /* Connection.swift in Sources */,
149BC80728FEAEB000D27A6D /* DnsResolver.swift in Sources */,
);
@@ -609,10 +661,10 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 14CD34D52D4F43B300789E6D /* PBXTargetDependency */ = {
+ 147F890E2E83CBC000BFD48B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 14CD34CB2D4F43B300789E6D /* Share Extension */;
- targetProxy = 14CD34D42D4F43B300789E6D /* PBXContainerItemProxy */;
+ target = 147F89042E83CBC000BFD48B /* ShareExtension */;
+ targetProxy = 147F890D2E83CBC000BFD48B /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
@@ -636,9 +688,9 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
- 14CD34D92D4F43B300789E6D /* Debug */ = {
+ 147F89102E83CBC000BFD48B /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FF85B414D2042FADD297DB3E /* Pods-Share Extension.debug.xcconfig */;
+ baseConfigurationReference = 584544DF38FA171ACDCA775B /* Pods-ShareExtension.debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@@ -648,7 +700,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
+ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
@@ -656,10 +708,10 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_FILE = "Share Extension/Info.plist";
- INFOPLIST_KEY_CFBundleDisplayName = "Share Extension";
+ INFOPLIST_FILE = ShareExtension/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -669,20 +721,23 @@
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = "org.nkn.nmobile.Share-Extension";
+ PRODUCT_BUNDLE_IDENTIFIER = org.nkn.nmobile.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
- 14CD34DA2D4F43B300789E6D /* Release */ = {
+ 147F89112E83CBC000BFD48B /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 2F1390E9C951F8699CC4CC1B /* Pods-Share Extension.release.xcconfig */;
+ baseConfigurationReference = 7F6144DC7E3F6B8544F0EE4F /* Pods-ShareExtension.release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@@ -692,7 +747,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
+ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
@@ -700,10 +755,10 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_FILE = "Share Extension/Info.plist";
- INFOPLIST_KEY_CFBundleDisplayName = "Share Extension";
+ INFOPLIST_FILE = ShareExtension/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -712,18 +767,21 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = "org.nkn.nmobile.Share-Extension";
+ PRODUCT_BUNDLE_IDENTIFIER = org.nkn.nmobile.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
- 14CD34DB2D4F43B300789E6D /* Profile */ = {
+ 147F89122E83CBC000BFD48B /* Profile */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 00DDD0F3B83E3CC2A5212805 /* Pods-Share Extension.profile.xcconfig */;
+ baseConfigurationReference = 3C6D0BD6B5E0E014F40856BD /* Pods-ShareExtension.profile.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@@ -733,7 +791,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
+ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
@@ -741,10 +799,10 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_FILE = "Share Extension/Info.plist";
- INFOPLIST_KEY_CFBundleDisplayName = "Share Extension";
+ INFOPLIST_FILE = ShareExtension/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -753,10 +811,13 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = "org.nkn.nmobile.Share-Extension";
+ PRODUCT_BUNDLE_IDENTIFIER = org.nkn.nmobile.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -804,7 +865,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -817,13 +878,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 330;
+ CURRENT_PROJECT_VERSION = 364;
DEVELOPMENT_TEAM = 67P82ZQDAS;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -889,7 +949,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -939,7 +999,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -954,13 +1014,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 330;
+ CURRENT_PROJECT_VERSION = 364;
DEVELOPMENT_TEAM = 67P82ZQDAS;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -983,13 +1042,12 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 330;
+ CURRENT_PROJECT_VERSION = 364;
DEVELOPMENT_TEAM = 67P82ZQDAS;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -1010,12 +1068,12 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- 14CD34D82D4F43B300789E6D /* Build configuration list for PBXNativeTarget "Share Extension" */ = {
+ 147F89142E83CBC000BFD48B /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 14CD34D92D4F43B300789E6D /* Debug */,
- 14CD34DA2D4F43B300789E6D /* Release */,
- 14CD34DB2D4F43B300789E6D /* Profile */,
+ 147F89102E83CBC000BFD48B /* Debug */,
+ 147F89112E83CBC000BFD48B /* Release */,
+ 147F89122E83CBC000BFD48B /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 37be44085..1a6f25533 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
Bool {
super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ FirebaseApp.configure()
+
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
@@ -23,25 +25,14 @@ import receive_sharing_intent
Crypto.register(controller: controller)
EthResolver.register(controller: controller)
DnsResolver.register(controller: controller)
-
+ SearchService.register(controller: controller)
+
registerNotification();
-
- // NotificationCenter.default.addObserver(self, selector:#selector(becomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
- // NotificationCenter.default.addObserver(self, selector:#selector(becomeDeath), name: UIApplication.didEnterBackgroundNotification, object: nil)
-
+
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
- // return true; // FIXED: with no share data
}
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
- let sharingIntent = SwiftReceiveSharingIntentPlugin.instance
- if sharingIntent.hasMatchingSchemePrefix(url: url) {
- return sharingIntent.application(app, open: url, options: options)
- }
-
- // For example
- // return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[.sourceApplication] as? String)
- // return false
return super.application(app, open: url, options:options)
}
@@ -67,36 +58,13 @@ import receive_sharing_intent
}
}
-// @objc func becomeActive(noti:Notification) {
-// //APNSPushService.shared().connectAPNS()
-// }
-
-// @objc func becomeDeath(noti:Notification) {
-// APNSPushService.shared().disConnectAPNS()
-// }
-
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// deviceToken = 32 bytes
let formatDeviceToken = deviceToken.map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
print("Application - GetDeviceToken - token = \(formatDeviceToken)")
UserDefaults.standard.setValue(formatDeviceToken, forKey: "nkn_device_token")
-
-// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
-// APNSPushService.shared().connectAPNS();
-// }
}
-// override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
-// print("Application - didReceiveRemoteNotification - onReceive - userInfo = \(userInfo)")
-// let aps = userInfo["aps"] as? [String: Any]
-// let alert = aps?["alert"] as? [String: Any]
-// var resultMap: [String: Any] = [String: Any]()
-// resultMap["title"] = alert?["title"]
-// resultMap["content"] = alert?["body"]
-// resultMap["isApplicationForeground"] = application.applicationState == UIApplication.State.active
-// Common.eventAdd(name: "onRemoteMessageReceived", map: resultMap)
-// }
-
override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
{
let userInfo = notification.request.content.userInfo
@@ -108,25 +76,10 @@ import receive_sharing_intent
resultMap["content"] = alert?["body"]
resultMap["isApplicationForeground"] = UIApplication.shared.applicationState == UIApplication.State.active
Common.eventAdd(name: "onRemoteMessageReceived", map: resultMap)
- // completionHandler([.alert, .badge, .sound]) // show notification on flutter, not here
}
-// override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
-// let userInfo = response.notification.request.content.userInfo
-// print("Application - userNotificationCenter - onClick - userInfo = \(userInfo)")
-// let aps = userInfo["aps"] as? [String: Any]
-// let alert = aps?["alert"] as? [String: Any]
-// var resultMap: [String: Any] = [String: Any]()
-// resultMap["title"] = alert?["title"]
-// resultMap["content"] = alert?["body"]
-// resultMap["isApplicationForeground"] = UIApplication.shared.applicationState == UIApplication.State.active
-// Common.eventAdd(name: "onNotificationClick", map: resultMap)
-// completionHandler()
-// }
-
override func applicationWillResignActive(_ application: UIApplication) {
window?.addSubview(self.visualEffectView)
-
}
override func applicationDidEnterBackground(_ application: UIApplication) {
diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist
new file mode 100644
index 000000000..2abdc5030
--- /dev/null
+++ b/ios/Runner/GoogleService-Info.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ CLIENT_ID
+ 980911608673-jsfne43egn1j5595bh58qqiohqu09hut.apps.googleusercontent.com
+ REVERSED_CLIENT_ID
+ com.googleusercontent.apps.980911608673-jsfne43egn1j5595bh58qqiohqu09hut
+ API_KEY
+ AIzaSyAi6yXWU62vUrE65e2xq-zGyzPRvCmKhGo
+ GCM_SENDER_ID
+ 980911608673
+ PLIST_VERSION
+ 1
+ BUNDLE_ID
+ org.nkn.nmobile
+ PROJECT_ID
+ nmobile
+ STORAGE_BUCKET
+ nmobile.firebasestorage.app
+ IS_ADS_ENABLED
+
+ IS_ANALYTICS_ENABLED
+
+ IS_APPINVITE_ENABLED
+
+ IS_GCM_ENABLED
+
+ IS_SIGNIN_ENABLED
+
+ GOOGLE_APP_ID
+ 1:980911608673:ios:c30a977e5c3c89df5d6b20
+ DATABASE_URL
+ https://nmobile.firebaseio.com
+
+
\ No newline at end of file
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index ed86aab98..f5934c853 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -2,22 +2,21 @@
- AppGroupId
- $(CUSTOM_GROUP_ID)
- CFBundleURLTypes
-
-
- CFBundleTypeRole
- Editor
- CFBundleURLName
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleURLSchemes
-
- ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)
-
-
-
-
+ UIDesignRequiresCompatibility
+
+ AppGroupId
+ $(CUSTOM_GROUP_ID)
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLSchemes
+
+ ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)
+
+
+
BGTaskSchedulerPermittedIdentifiers
org.nkn.nmobile.backgroundtask
@@ -63,6 +62,24 @@
LSSupportsOpeningDocumentsInPlace
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeName
+ ShareHandler
+ LSHandlerRank
+ Alternate
+ LSItemContentTypes
+
+ public.file-url
+ public.image
+ public.text
+ public.movie
+ public.url
+ public.data
+
+
+
NSAppTransportSecurity
NSAllowsArbitraryLoads
diff --git a/ios/Share Extension/Info.plist b/ios/Share Extension/Info.plist
deleted file mode 100644
index 2ef9ea0a9..000000000
--- a/ios/Share Extension/Info.plist
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
- AppGroupId
- $(CUSTOM_GROUP_ID)
- CFBundleVersion
- $(FLUTTER_BUILD_NUMBER)
- NSExtension
-
- NSExtensionAttributes
-
- PHSupportedMediaTypes
-
-
- Video
-
- Image
-
- NSExtensionActivationRule
-
-
- NSExtensionActivationSupportsText
-
-
- NSExtensionActivationSupportsWebURLWithMaxCount
- 1
-
- NSExtensionActivationSupportsImageWithMaxCount
- 100
-
- NSExtensionActivationSupportsMovieWithMaxCount
- 100
-
-
- NSExtensionActivationSupportsFileWithMaxCount
- 1
-
-
- NSExtensionMainStoryboard
- MainInterface
- NSExtensionPointIdentifier
- com.apple.share-services
-
-
-
\ No newline at end of file
diff --git a/ios/Share Extension/ShareViewController.swift b/ios/Share Extension/ShareViewController.swift
deleted file mode 100644
index 90f1bc8a7..000000000
--- a/ios/Share Extension/ShareViewController.swift
+++ /dev/null
@@ -1,38 +0,0 @@
-// If you get no such module 'receive_sharing_intent' error.
-// Go to Build Phases of your Runner target and
-// move `Embed Foundation Extension` to the top of `Thin Binary`.
-import receive_sharing_intent
-
-class ShareViewController: RSIShareViewController {
-
- // Use this method to return false if you don't want to redirect to host app automatically.
- // Default is true
- override func shouldAutoRedirect() -> Bool {
- return false
- }
-
-}
-
-//import UIKit
-//import Social
-//
-//class ShareViewController: SLComposeServiceViewController {
-//
-// override func isContentValid() -> Bool {
-// // Do validation of contentText and/or NSExtensionContext attachments here
-// return true
-// }
-//
-// override func didSelectPost() {
-// // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
-//
-// // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
-// self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
-// }
-//
-// override func configurationItems() -> [Any]! {
-// // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
-// return []
-// }
-//
-//}
diff --git a/ios/Share Extension/Base.lproj/MainInterface.storyboard b/ios/ShareExtension/Base.lproj/MainInterface.storyboard
similarity index 100%
rename from ios/Share Extension/Base.lproj/MainInterface.storyboard
rename to ios/ShareExtension/Base.lproj/MainInterface.storyboard
diff --git a/ios/ShareExtension/Info.plist b/ios/ShareExtension/Info.plist
new file mode 100644
index 000000000..67c8910d3
--- /dev/null
+++ b/ios/ShareExtension/Info.plist
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ NSExtension
+
+ NSExtensionAttributes
+
+
+ IntentsSupported
+
+ INSendMessageIntent
+
+
+ NSExtensionActivationRule
+
+
+
+ SUBQUERY (
+ extensionItems,
+ $extensionItem,
+ SUBQUERY (
+ $extensionItem.attachments,
+ $attachment,
+ (
+ ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.file-url"
+ || ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image"
+ || ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.text"
+ || ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.movie"
+ || ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
+ )
+ ).@count > 0
+ ).@count > 0
+
+ PHSupportedMediaTypes
+
+ Video
+ Image
+
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.share-services
+
+
+
\ No newline at end of file
diff --git a/ios/Share Extension/Share Extension.entitlements b/ios/ShareExtension/ShareExtension.entitlements
similarity index 100%
rename from ios/Share Extension/Share Extension.entitlements
rename to ios/ShareExtension/ShareExtension.entitlements
diff --git a/ios/ShareExtension/ShareViewController.swift b/ios/ShareExtension/ShareViewController.swift
new file mode 100644
index 000000000..b17cff89c
--- /dev/null
+++ b/ios/ShareExtension/ShareViewController.swift
@@ -0,0 +1,3 @@
+import share_handler_ios_models
+
+class ShareViewController: ShareHandlerIosViewController {}
diff --git a/lib/app.dart b/lib/app.dart
index 05e0e85bb..978c69f12 100644
--- a/lib/app.dart
+++ b/lib/app.dart
@@ -16,11 +16,12 @@ import 'package:nmobile/native/common.dart';
import 'package:nmobile/schema/wallet.dart';
import 'package:nmobile/screens/chat/home.dart';
import 'package:nmobile/screens/settings/home.dart';
-import 'package:nmobile/screens/wallet/home.dart';
import 'package:nmobile/services/task.dart';
import 'package:nmobile/utils/asset.dart';
import 'package:nmobile/utils/logger.dart';
-import 'package:receive_sharing_intent/receive_sharing_intent.dart';
+import 'package:share_handler/share_handler.dart';
+
+import 'upgrade/upgrade_checker.dart';
class AppScreen extends StatefulWidget {
static const String routeName = '/';
@@ -62,6 +63,7 @@ class _AppScreenState extends State with WidgetsBindingObserver {
Completer loginCompleter = Completer();
bool isAuthProgress = false;
+ SharedMedia? media;
@override
void initState() {
@@ -80,6 +82,8 @@ class _AppScreenState extends State with WidgetsBindingObserver {
// await backgroundFetchService.install();
await localNotification.init();
await audioHelper.init();
+
+ UpgradeChecker.checkAndShowDialog(Settings.appContext);
});
application.mounted(); // await
@@ -117,25 +121,25 @@ class _AppScreenState extends State with WidgetsBindingObserver {
}
});
- // For sharing images coming from outside the app while the app is in the memory
- _intentDataMediaStreamSubscription = ReceiveSharingIntent.instance.getMediaStream().listen((List? values) async {
- if (values == null || values.isEmpty) return;
- await loginCompleter.future;
- ShareHelper.showWithFiles(this.context, values);
- }, onError: (err, stack) {
- handleError(err, stack);
- });
+ initPlatformState();
+ // wallet
+ taskService.addTask(TaskService.KEY_WALLET_BALANCE, 60, (key) => walletCommon.queryAllBalance(), delayMs: 1 * 1000);
+ }
+
+ Future initPlatformState() async {
+ final handler = ShareHandlerPlatform.instance;
+ media = await handler.getInitialSharedMedia();
- // For sharing images coming from outside the app while the app is closed
- ReceiveSharingIntent.instance.getInitialMedia().then((List? values) async {
- if (values == null || values.isEmpty) return;
+ handler.sharedMediaStream.listen((SharedMedia media) async {
+ if (media.attachments?.isNotEmpty != true) return;
+ if (!mounted) return;
+ this.media = media;
await loginCompleter.future;
- ShareHelper.showWithFiles(this.context, values);
+ ShareHelper.showWithFiles(this.context, media);
});
+ if (!mounted) return;
-
- // wallet
- taskService.addTask(TaskService.KEY_WALLET_BALANCE, 60, (key) => walletCommon.queryAllBalance(), delayMs: 1 * 1000);
+ setState(() {});
}
@override
@@ -216,12 +220,12 @@ class _AppScreenState extends State with WidgetsBindingObserver {
@override
Widget build(BuildContext context) {
- return WillPopScope(
- onWillPop: () async {
- if (Platform.isAndroid) {
+ return PopScope(
+ canPop: false,
+ onPopInvokedWithResult: (didPop, result) async {
+ if (!didPop && Platform.isAndroid) {
await Common.backDesktop();
}
- return false;
},
child: Scaffold(
backgroundColor: application.theme.backgroundColor,
diff --git a/lib/common/application.dart b/lib/common/application.dart
index 45066dac8..6368ddf04 100644
--- a/lib/common/application.dart
+++ b/lib/common/application.dart
@@ -9,6 +9,7 @@ import 'package:nmobile/utils/logger.dart';
typedef Func = Future Function();
class Application {
+ static const env = String.fromEnvironment("APP_ENV", defaultValue: "production");
List _initializeFutures = [];
List _mountedFutures = [];
@@ -33,6 +34,10 @@ class Application {
int goBackgroundAt = 0;
int goForegroundAt = 0;
+
+ bool get isDev => env == "development";
+ bool get isProd => env == "production";
+
Application();
void init() {
@@ -48,7 +53,20 @@ class Application {
goForegroundAt = DateTime.now().millisecondsSinceEpoch;
_appLifeSink.add(false);
} else {
- logger.d("Application - appLifeStream - nothing - states:$states");
+ if (states.length >= 2 && states[1] == AppLifecycleState.paused && !inBackGround && !inSystemSelecting) {
+ logger.i("Application - appLifeStream - in background (missed detection) - states:$states");
+ inBackGround = true;
+ goBackgroundAt = DateTime.now().millisecondsSinceEpoch;
+ _appLifeSink.add(true);
+ }
+ else if (states.length >= 2 && states[1] == AppLifecycleState.resumed && inBackGround) {
+ logger.i("Application - appLifeStream - in foreground (missed detection) - states:$states");
+ inBackGround = false;
+ goForegroundAt = DateTime.now().millisecondsSinceEpoch;
+ _appLifeSink.add(false);
+ } else {
+ logger.d("Application - appLifeStream - nothing - states:$states");
+ }
}
});
}
@@ -77,11 +95,14 @@ class Application {
await Future.wait(futures);
}
- // resumed -> inactive -> paused
+ // resumed -> inactive -> hidden -> paused (iOS with hidden state)
+ // resumed -> inactive -> paused (iOS without hidden state / Android)
bool _isGoBackground(List states) {
if (states.length >= 2) {
if (Platform.isIOS) {
- return !inSystemSelecting && (states[0] == AppLifecycleState.inactive) && (states[1] == AppLifecycleState.paused);
+ return !inSystemSelecting &&
+ ((states[0] == AppLifecycleState.inactive && states[1] == AppLifecycleState.paused) ||
+ (states[0] == AppLifecycleState.hidden && states[1] == AppLifecycleState.paused));
} else if (Platform.isAndroid) {
return !inSystemSelecting && (states[0] == AppLifecycleState.inactive) && (states[1] == AppLifecycleState.paused);
}
@@ -89,12 +110,18 @@ class Application {
return false;
}
- // paused -> inactive(just ios) -> resumed
+ // paused -> hidden -> inactive -> resumed (iOS with hidden state)
+ // paused -> inactive -> resumed (iOS without hidden state)
+ // paused -> resumed (Android)
bool _isFromBackground(List states) {
if (states.length >= 2) {
if (Platform.isIOS) {
- return inBackGround && (states[0] == AppLifecycleState.paused) && (states[1] == AppLifecycleState.inactive);
+ return inBackGround &&
+ ((states[0] == AppLifecycleState.paused && states[1] == AppLifecycleState.resumed) ||
+ (states[0] == AppLifecycleState.hidden && states[1] == AppLifecycleState.resumed) ||
+ (states[0] == AppLifecycleState.inactive && states[1] == AppLifecycleState.resumed));
} else if (Platform.isAndroid) {
+ // Android: paused -> resumed
return inBackGround && (states[0] == AppLifecycleState.paused) && (states[1] == AppLifecycleState.resumed);
}
}
diff --git a/lib/common/authentication.dart b/lib/common/authentication.dart
index 0e7b66a37..bbda0fa11 100644
--- a/lib/common/authentication.dart
+++ b/lib/common/authentication.dart
@@ -64,7 +64,13 @@ class Authorization {
String? pwd;
try {
pwd = await walletCommon.getPassword(walletAddress);
- if (!authOk || pwd == null || pwd.isEmpty) {
+ // Default Account / empty password wallet: skip dialog, use empty password to login
+ if (pwd == '' && Settings.biometricsAuthentication) {
+ return null;
+ } else if (pwd == '') {
+ return '';
+ }
+ if (!authOk || pwd == null) {
onInput?.call(true);
String? password = await BottomDialog.of(Settings.appContext).showInput(
title: Settings.locale((s) => s.verify_wallet_password),
diff --git a/lib/common/chat/chat_in.dart b/lib/common/chat/chat_in.dart
index 26ca5b5aa..a7c604dd6 100644
--- a/lib/common/chat/chat_in.dart
+++ b/lib/common/chat/chat_in.dart
@@ -18,6 +18,8 @@ import 'package:nmobile/utils/logger.dart';
import 'package:nmobile/utils/parallel_queue.dart';
import 'package:nmobile/utils/path.dart';
+import '../../storages/message.dart';
+
class ChatInCommon with Tag {
ChatInCommon();
@@ -167,6 +169,12 @@ class ChatInCommon with Tag {
}
}
}
+ bool blocked = await contactCommon.isBlocked(received.sender);
+ if (blocked) {
+ logger.w("$TAG - _handleMessage - blocked - store as deleted - sender:${received.sender} - targetId:${received.targetId} - type:${received.contentType}");
+ received.isDelete = true;
+ received.deleteAt = DateTime.now().millisecondsSinceEpoch;
+ }
// receive
switch (received.contentType) {
case MessageContentType.ping:
@@ -229,6 +237,9 @@ class ChatInCommon with Tag {
case MessageContentType.topicKickOut:
await _receiveTopicKickOut(received);
break;
+ case MessageContentType.revoke:
+ await _receiveRevoke(received);
+ break;
case MessageContentType.privateGroupInvitation:
insertOk = await _receivePrivateGroupInvitation(received);
break;
@@ -942,6 +953,25 @@ class ChatInCommon with Tag {
await privateGroupCommon.updatePrivateGroupMembers(received.sender, groupId, version, members);
}
+ Future _receiveRevoke(MessageSchema received) async {
+ // content is target msgId
+ String? targetMsgId = received.content?.toString();
+ if (targetMsgId == null || targetMsgId.isEmpty) return false;
+ MessageSchema? target = await messageCommon.query(targetMsgId);
+ if (target == null) return false;
+ // Only sender can revoke
+ String sender = received.sender;
+ bool isSameSender = target.isOutbound
+ ? (clientCommon.address == sender)
+ : (target.sender == sender);
+ if (!isSameSender) return false;
+ // Soft delete first
+ await MessageStorage.instance.updateIsDelete(target.msgId, true);
+ // Optional: deep delete pieces/content
+ await messageCommon.messageDelete(target, notify: true);
+ return true;
+ }
+
Future _deletePieces(String msgId) async {
final limit = 20;
List pieces = [];
diff --git a/lib/common/chat/chat_out.dart b/lib/common/chat/chat_out.dart
index 63ac72041..0ac09bb8a 100644
--- a/lib/common/chat/chat_out.dart
+++ b/lib/common/chat/chat_out.dart
@@ -233,7 +233,7 @@ class ChatOutCommon with Tag {
if (notification && (contact != null) && !contact.isMe) {
deviceInfoCommon.queryDeviceTokenList(contact.address).then((tokens) async {
logger.d("$TAG - _sendWithContact - push notification - count:${tokens.length} - target:${contact.address} - tokens:$tokens");
- List results = await RemoteNotification.send(tokens);
+ List results = await RemoteNotification.send(tokens, targetAddress: contact.address);
if (results.isNotEmpty) {
message.options = MessageOptions.setPushNotifyId(message.options, results[0]);
await messageCommon.updateMessageOptions(message, message.options, notify: false);
@@ -320,7 +320,7 @@ class ChatOutCommon with Tag {
if (_contact.isMe) continue;
deviceInfoCommon.queryDeviceTokenList(_contact.address).then((tokens) {
logger.d("$TAG - _sendWithTopic - push notification - count:${tokens.length} - target:${_contact.address} - topic:${topic.topicId} - tokens:$tokens");
- RemoteNotification.send(tokens); // await // no need result
+ RemoteNotification.send(tokens, targetAddress: _contact.address); // await // no need result
});
}
});
@@ -388,7 +388,7 @@ class ChatOutCommon with Tag {
if (_contact.isMe) continue;
deviceInfoCommon.queryDeviceTokenList(_contact.address).then((tokens) {
logger.d("$TAG - _sendWithPrivateGroup - push notification - count:${tokens.length} - target:${_contact.address} - groupId:${group.groupId} - tokens:$tokens");
- RemoteNotification.send(tokens); // await // no need result
+ RemoteNotification.send(tokens, targetAddress: _contact.address); // await // no need result
});
}
});
@@ -865,6 +865,41 @@ class ChatOutCommon with Tag {
return await _sendVisible(message, maxHoldingSeconds: maxHoldingSeconds);
}
+ Future sendRevoke(String msgId) async {
+ if (msgId.isEmpty) return false;
+ // Only allow sender to revoke
+ MessageSchema? origin = await messageCommon.query(msgId);
+ if (origin == null || !origin.isOutbound) return false;
+
+ String targetId = origin.targetId;
+ int targetType = origin.targetType;
+ // Build revoke message schema per target type
+ MessageSchema revoke = MessageSchema.fromSend(
+ targetId,
+ targetType,
+ MessageContentType.revoke,
+ msgId,
+ );
+ // no DB persistence for revoke command
+ revoke.data = MessageData.getRevoke(msgId);
+
+ // Send according to targetType
+ Uint8List? pid;
+ if (targetType == SessionType.TOPIC) {
+ TopicSchema? topic = TopicSchema.create(targetId, type: SessionType.TOPIC);
+ pid = await _sendWithTopic(topic, revoke, notification: false);
+ } else if (targetType == SessionType.PRIVATE_GROUP) {
+ PrivateGroupSchema? group = PrivateGroupSchema.create(targetId, targetId, type: SessionType.PRIVATE_GROUP);
+ pid = await _sendWithPrivateGroup(group, revoke, notification: false);
+ } else {
+ ContactSchema? contact = await chatCommon.contactHandle(revoke);
+ pid = await _sendWithContact(contact, revoke, notification: false);
+ }
+ bool ok = pid?.isNotEmpty == true;
+ logger.i("$TAG - sendRevoke - type:$targetType - dest:$targetId - msgId:$msgId - ok:$ok");
+ return ok;
+ }
+
Future saveIpfs(dynamic target, Map data) async {
// content
String contentPath = data["path"]?.toString() ?? "";
diff --git a/lib/common/client/client.dart b/lib/common/client/client.dart
index 5fcfad2d8..f95a182f0 100644
--- a/lib/common/client/client.dart
+++ b/lib/common/client/client.dart
@@ -188,15 +188,12 @@ class ClientCommon with Tag {
}
}
if (c != null) {
- logger.i("$TAG - signIn - try success - tryTimes:$tryTimes - address:${c.address} - wallet:$wallet - password:$password");
success = true;
break;
} else if (!canTry) {
- logger.e("$TAG - signIn - try broken - tryTimes:$tryTimes - address:${c?.address} - wallet:$wallet - password:$password");
await signOut(clearWallet: true, closeDB: true, lock: false);
break;
}
- logger.w("$TAG - signIn - try again - tryTimes:$tryTimes - wallet:$wallet - password:$password");
if ((tryTimes > 0) && isNetworkOk) await RPC.setRpcServers(wallet.address, []);
tryTimes++;
_statusSink.add(ClientConnectStatus.connecting); // need flush
@@ -215,11 +212,11 @@ class ClientCommon with Tag {
logger.w("$TAG - _signIn - wait network ok");
await Future.delayed(Duration(milliseconds: 500));
}
- // password
+ // password (allow empty string if stored password is empty)
try {
- if ((password == null) || password.isEmpty) {
+ if (password == null) {
logger.w("$TAG - _signIn - password is null - wallet:$wallet");
- return {"client": null, "canTry": false}; // , "text": "password empty"
+ return {"client": null, "canTry": false};
}
if (!(await walletCommon.isPasswordRight(wallet.address, password))) {
logger.w("$TAG - _signIn - password error - wallet:$wallet");
@@ -340,7 +337,7 @@ class ClientCommon with Tag {
await chatInCommon.waitReceiveQueues("_signOut"); // wait db_insert from onMessage
await chatInCommon.pause(reset: closeDB);
client = null;
- if (clearWallet) BlocProvider.of(Settings.appContext).add(DefaultWallet(null));
+
if (closeDB) await dbCommon.close();
return true;
} catch (e, st) {
@@ -470,15 +467,12 @@ class ClientCommon with Tag {
bool canTry = result["canTry"];
password = result["password"]?.toString();
if (c != null) {
- logger.i("$TAG - reconnect - try success - tryTimes:$tryTimes - address:${c.address} - wallet:$wallet - password:$password");
success = true;
break;
} else if (!canTry) {
- logger.e("$TAG - reconnect - try broken - tryTimes:$tryTimes - address:${c?.address} - wallet:$wallet - password:$password");
await signOut(clearWallet: true, closeDB: true, lock: false);
break;
}
- logger.w("$TAG - reconnect - try again - tryTimes:$tryTimes - wallet:$wallet - password:$password");
if ((tryTimes > 0) && isNetworkOk) await RPC.setRpcServers(wallet.address, []);
tryTimes++;
_statusSink.add(ClientConnectStatus.connecting); // need first flush
diff --git a/lib/common/contact/contact.dart b/lib/common/contact/contact.dart
index b9bd02095..21b4b95bd 100644
--- a/lib/common/contact/contact.dart
+++ b/lib/common/contact/contact.dart
@@ -1,5 +1,7 @@
import 'dart:async';
+import 'dart:typed_data';
+import 'package:nkn_sdk_flutter/utils/hex.dart';
import 'package:nmobile/common/locator.dart';
import 'package:nmobile/common/name_service/resolver.dart';
import 'package:nmobile/helpers/error.dart';
@@ -11,10 +13,14 @@ import 'package:nmobile/utils/logger.dart';
import 'package:nmobile/utils/path.dart';
import 'package:uuid/uuid.dart';
+import '../search_service/search_service.dart';
+
class ContactCommon with Tag {
// ignore: close_sinks
StreamController _addController = StreamController.broadcast();
+
StreamSink get _addSink => _addController.sink;
+
Stream get addStream => _addController.stream;
// ignore: close_sinks
@@ -24,12 +30,16 @@ class ContactCommon with Tag {
// ignore: close_sinks
StreamController _updateController = StreamController.broadcast();
+
StreamSink get _updateSink => _updateController.sink;
+
Stream get updateStream => _updateController.stream;
// ignore: close_sinks
StreamController _meUpdateController = StreamController.broadcast();
+
StreamSink get meUpdateSink => _meUpdateController.sink;
+
Stream get meUpdateStream => _meUpdateController.stream;
ContactCommon();
@@ -58,12 +68,26 @@ class ContactCommon with Tag {
if ((address == null) || address.isEmpty) return null;
// address
String? clientAddress;
- try {
- Resolver resolver = Resolver();
- clientAddress = await resolver.resolve(address);
- } catch (e, st) {
- handleError(e, st);
+ // TODO
+ // try {
+ // Resolver resolver = Resolver();
+ // clientAddress = await resolver.resolve(address);
+ // } catch (e, st) {
+ // handleError(e, st);
+ // }
+
+ if (clientAddress == null) {
+ Uint8List? seed = clientCommon.getSeed();
+ if (seed == null) {
+ String? walletAddress = await walletCommon.getDefaultAddress();
+ seed = hexDecode(await walletCommon.getSeed(walletAddress));
+ }
+ final service = await SearchService.createWithAuth(seed: seed);
+
+ final response = await service.queryByID(address);
+ clientAddress = response?.nknAddress;
}
+
bool resolveOk = false;
if ((clientAddress != null) && Validate.isNknChatIdentifierOk(clientAddress)) {
resolveOk = true;
@@ -106,10 +130,11 @@ class ContactCommon with Tag {
List contacts = await queryList(type: ContactType.me, orderDesc: false, limit: 1);
String myAddress = selfAddress ?? clientCommon.address ?? "";
// TODO: fix multiple me
- for(int i = 0; i < contacts.length; i++) {
+ // Iterate backwards so remove() does not shift indices we haven't visited
+ for (int i = contacts.length - 1; i >= 0; i--) {
if (myAddress.isNotEmpty && contacts[i].address != myAddress) {
await setType(contacts[i].address, ContactType.none, notify: false);
- contacts.remove(contacts[i]);
+ contacts.removeAt(i);
}
}
@@ -422,6 +447,31 @@ class ContactCommon with Tag {
return data;
}
+ Future isBlocked(String? address) async {
+ if (address == null || address.isEmpty) return false;
+ ContactSchema? contact = await query(address, fetchWalletAddress: false);
+ if (contact == null) return false;
+ var value = contact.data['blocked'];
+ if (value is bool) return value;
+ if (value is num) return value != 0;
+ String str = value?.toString().toLowerCase() ?? "";
+ return str == "1" || str == "true";
+ }
+
+ Future