Skip to content

Commit

Permalink
fix!: handle multiple intents
Browse files Browse the repository at this point in the history
  • Loading branch information
ookami-kb committed May 27, 2023
1 parent 8f58fed commit 484a092
Show file tree
Hide file tree
Showing 19 changed files with 810 additions and 308 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.solana.solana_mobile_wallet

import android.content.Context
import android.content.Intent
import android.util.Log
import com.solana.mobilewalletadapter.walletlib.association.AssociationUri
import com.solana.mobilewalletadapter.walletlib.association.LocalAssociationUri
import com.solana.mobilewalletadapter.walletlib.authorization.AuthIssuerConfig
import com.solana.mobilewalletadapter.walletlib.protocol.MobileWalletAdapterConfig
import com.solana.mobilewalletadapter.walletlib.scenario.Scenario
import io.flutter.plugin.common.BinaryMessenger

class ApiHost(private val context: Context, private val api: Api.ApiFlutter) : Api.ApiHost {
private val scenarios = mutableMapOf<Long, Scenario>()
private var intent: Intent? = null

fun setIntent(intent: Intent) {
this.intent = intent
}

fun init(binaryMessenger: BinaryMessenger) {
Api.ApiHost.setup(binaryMessenger, this)
}

private fun register(id: Long, scenario: Scenario) {
scenarios[id] = scenario
}

private fun unregister(id: Long) {
scenarios.remove(id)
}

override fun start(id: Long) {
scenarios[id]?.start()
}

override fun close(id: Long) {
scenarios[id]?.close()
}

override fun createScenario(
id: Long,
walletConfig: Api.WalletConfigDto,
authIssuerConfig: Api.AuthIssuerConfigDto,
result: Api.Result<ByteArray>?
) {
val intent = this.intent
if (intent == null) {
result?.success(null)
} else {
val associationUri = intent.data?.let { uri -> AssociationUri.parse(uri) }

if (associationUri == null) {
Log.e(TAG, "Unsupported association URI '${intent.data}'")
result?.success(null)
return
} else if (associationUri !is LocalAssociationUri) {
result?.error(NotImplementedError())
Log.w(TAG, "Current implementation of wallet does not support remote clients")
return
}

Log.e(TAG, "Supported URI: $associationUri")

val scenario = associationUri.createScenario(
context,
MobileWalletAdapterConfig(
walletConfig.supportsSignAndSendTransactions,
walletConfig.maxTransactionsPerSigningRequest.toInt(),
walletConfig.maxMessagesPerSigningRequest.toInt(),
walletConfig.supportedTransactionVersions.toTypedArray(),
walletConfig.noConnectionWarningTimeoutInMs,
),
AuthIssuerConfig(
authIssuerConfig.name,
authIssuerConfig.maxOutstandingTokensPerIdentility.toInt(),
authIssuerConfig.authorizationValidityInMs,
authIssuerConfig.reauthorizationValidityInMs,
authIssuerConfig.reauthorizationValidityInMs,
),
Callbacks(id, api) { unregister(id) },
)
register(id, scenario)

result?.success(scenario.associationPublicKey)
}
}


companion object {
private const val TAG = "SolanaMobileWalletPlugin"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,12 @@ import android.net.Uri
import android.os.Handler
import android.os.Looper
import com.solana.mobilewalletadapter.walletlib.scenario.*
import io.flutter.plugin.common.BinaryMessenger

object ApiHost : Api.ApiHost {
private val scenarios = mutableMapOf<Long, Scenario>()

fun init(binaryMessenger: BinaryMessenger) {
Api.ApiHost.setup(binaryMessenger, this)
}

fun register(id: Long, scenario: Scenario) {
scenarios[id] = scenario
}

fun unregister(id: Long) {
scenarios.remove(id)
}

override fun start(id: Long) {
scenarios[id]?.start()
}

override fun close(id: Long) {
scenarios[id]?.close()
}
}

class Callbacks(
private val id: Long,
binaryMessenger: BinaryMessenger,
private val api: Api.ApiFlutter,
private val onTeardownComplete: () -> Unit
) : LocalScenario.Callbacks {
private val api = Api.ApiFlutter(binaryMessenger)

override fun onScenarioReady() {
Handler(Looper.getMainLooper()).post { api.onScenarioReady(id) {} }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,105 +1,51 @@
package com.solana.solana_mobile_wallet

import android.content.Context
import android.content.Intent
import android.util.Log
import android.os.Handler
import android.os.Looper
import androidx.annotation.NonNull
import com.solana.mobilewalletadapter.walletlib.association.AssociationUri
import com.solana.mobilewalletadapter.walletlib.association.LocalAssociationUri
import com.solana.mobilewalletadapter.walletlib.authorization.AuthIssuerConfig
import com.solana.mobilewalletadapter.walletlib.protocol.MobileWalletAdapterConfig
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

class SolanaMobileWalletPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var channel: MethodChannel
private var intent: Intent? = null
private lateinit var context: Context
private lateinit var messenger: BinaryMessenger
class SolanaMobileWalletPlugin : FlutterPlugin, ActivityAware {
private var initialIntent = true
private lateinit var apiFlutter: Api.ApiFlutter
private lateinit var apiHost: ApiHost

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
messenger = flutterPluginBinding.binaryMessenger
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.solana.sms.wallet")
channel.setMethodCallHandler(this)
context = flutterPluginBinding.applicationContext

ApiHost.init(flutterPluginBinding.binaryMessenger)
apiFlutter = Api.ApiFlutter(flutterPluginBinding.binaryMessenger)
apiHost = ApiHost(flutterPluginBinding.applicationContext, apiFlutter)
apiHost.init(flutterPluginBinding.binaryMessenger)
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "createScenario") {
val intent = this.intent
if (intent == null) {
result.success(null)
} else {
val associationUri = intent.data?.let { uri -> AssociationUri.parse(uri) }

if (associationUri == null) {
Log.e(TAG, "Unsupported association URI '${intent.data}'")
result.success(null)
return
} else if (associationUri !is LocalAssociationUri) {
result.error("NotImplemented", "Not implemented", null)
Log.w(TAG, "Current implementation of wallet does not support remote clients")
return
}

Log.e(TAG, "Supported URI: $associationUri")

val arguments = call.arguments as Map<String, Any?>
val id = (arguments["id"] as Number).toLong()

val walletConfig = arguments["walletConfig"] as Map<String, Any?>
val issuerConfig = arguments["issuerConfig"] as Map<String, Any?>

val scenario = associationUri.createScenario(
context,
MobileWalletAdapterConfig(
walletConfig["supportsSignAndSendTransactions"] as Boolean,
walletConfig["maxTransactionsPerSigningRequest"] as Int,
walletConfig["maxMessagesPerSigningRequest"] as Int,
(walletConfig["supportedTransactionVersions"] as ArrayList<Object>).toArray(),
(walletConfig["noConnectionWarningTimeout"] as Number).toLong() / 1000,
),
AuthIssuerConfig(
issuerConfig["name"] as String,
issuerConfig["maxOutstandingTokensPerIdentity"] as Int,
(issuerConfig["authorizationValidity"] as Number).toLong() / 1000,
(issuerConfig["reauthorizationValidity"] as Number).toLong() / 1000,
(issuerConfig["reauthorizationNopDuration"] as Number).toLong() / 1000,
),
Callbacks(id, messenger) { ApiHost.unregister(id) },
)
ApiHost.register(id, scenario)

result.success(scenario.associationPublicKey)
}
} else {
result.notImplemented()
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
binding.addOnNewIntentListener(fun(intent: Intent?): Boolean {
intent?.let { handleIntent(it) }
return false
})
handleIntent(binding.activity.intent)
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
binding.addOnNewIntentListener(fun(intent: Intent?): Boolean {
intent?.let { handleIntent(it) }
return false
})
handleIntent(binding.activity.intent)
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
intent = binding.activity.intent
private fun handleIntent(intent: Intent) {
if (initialIntent) initialIntent = false
apiHost.setIntent(intent)
Handler(Looper.getMainLooper()).post { apiFlutter.onNewIntent(initialIntent) {} }
}

override fun onDetachedFromActivityForConfigChanges() = Unit

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) = Unit

override fun onDetachedFromActivity() = Unit

companion object {
private const val TAG = "SolanaMobileWalletPlugin"
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) = Unit
}
2 changes: 1 addition & 1 deletion packages/solana_mobile_wallet/example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
26 changes: 11 additions & 15 deletions packages/solana_mobile_wallet/example/lib/mobile_wallet/bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,7 @@ part 'state.dart';
class MobileWalletBloc extends Cubit<MobileWalletState>
implements ScenarioCallbacks {
MobileWalletBloc(this._keyPair) : super(const MobileWalletState.none()) {
_init();
}

Scenario? _scenario;
Completer<Object?>? _completer;

final Ed25519HDKeyPair _keyPair;
late final _client = RpcClient('https://api.testnet.solana.com');

Future<void> _init() async {
_scenario = await Scenario.create(
Api.instance.setup(
walletConfig: const MobileWalletAdapterConfig(
supportsSignAndSendTransactions: true,
maxTransactionsPerSigningRequest: 10,
Expand All @@ -34,8 +24,17 @@ class MobileWalletBloc extends Cubit<MobileWalletState>
issuerConfig: const AuthIssuerConfig(name: 'example_wallet'),
callbacks: this,
);
}

_scenario?.start();
Scenario? _scenario;
Completer<Object?>? _completer;

final Ed25519HDKeyPair _keyPair;
late final _client = RpcClient('https://api.testnet.solana.com');

@override
void onScenarioReady(Scenario scenario) {
_scenario = scenario;
}

Future<void> authorizeDapp({
Expand Down Expand Up @@ -341,9 +340,6 @@ class MobileWalletBloc extends Cubit<MobileWalletState>
@override
void onScenarioError() {}

@override
void onScenarioReady() {}

@override
void onScenarioServingClients() {}

Expand Down
Loading

0 comments on commit 484a092

Please sign in to comment.