Skip to content

Commit

Permalink
Merge pull request #23 from MetaMask/update-setup-documentation
Browse files Browse the repository at this point in the history
Update setup documentation
  • Loading branch information
elefantel authored Sep 8, 2023
2 parents 421dadc + 4abc18f commit 912ffd1
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 45 deletions.
96 changes: 89 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,26 @@ And then sync your project with the gradle settings. Once the syncing has comple

<b>Please note that this SDK requires MetaMask Mobile version 7.6.0 or higher</b>.

### 2. Import the SDK
### 2. Setup your app
#### 2.1 Gradle settings
We use Hilt for Dagger dependency injection, so you will need to add the corresponding dependencies.

In the project's root `build.gradle`,
```
import io.metamask.androidsdk
buildscript {
// other setup here
dependencies {
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.43.2'
}
}
plugins {
// other setup here
id 'com.google.dagger.hilt.android' version '2.43.2' apply false
}
```
We use Hilt for Dagger dependency injection, so you will need to add the corresponding dependencies in your `app/build.gradle`:

And then in your `app/build.gradle`:

```
plugins {
Expand All @@ -40,9 +55,77 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
}
```
#### 2.2 ViewModel Module Dependencies Injection
Since we use Hilt dependency injection, you will also need to create a module defining ethereum viewmodel injection. This is a single instance that will be shared across various view models and will survive configuration changes.

```
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import io.metamask.androidsdk.ApplicationRepository
import io.metamask.androidsdk.EthereumViewModel
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object EthereumViewModelModule {
@Provides
@Singleton
fun provideEthereumViewModel(repository: ApplicationRepository): EthereumViewModel {
return EthereumViewModel(repository)
}
}
```

#### 2.3 Setup Application Class
If you don't have an application class, you need to create one.
```
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class DappApplication : Application() {}
```
Then update `android:name` in the `AndroidManifest.xml` to this application class.

```
<manifest>
<application
android:name=".DappApplication"
...
</application>
</manifest>
```
#### 2.4 Add `@AndroidEntryPoint` to your Activity and Fragment
As a final step, if you need to inject your dependencies in an activity, you need to add `@AndroidEntryPoint` in your activity class. However, if you need to inject your dependencies in a fragment, then you need to add `@AndroidEntryPoint` in both the fragment and the activity that hosts the fragment.

```
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
// ...
}
```

```
@AndroidEntryPoint
class LoginFragment : Fragment() {
// ...
}
```

Refer to the example app for more details on how we set up a Jetpack Compose project to work with the SDK.

### 3. Connect your Dapp
### 3. Import the SDK
Now you can import the SDK and start using it.
```
import io.metamask.androidsdk.EthereumViewModel
// other imports as necessary
```

### 4. Connect your Dapp
The Ethereum module requires the app context, so you will need to instantiate it from an Activity or a module that injects a context.
```kotlin
// MainActivity
Expand All @@ -69,7 +152,7 @@ ethereumViewModel.connect(dapp) { result ->
We log three SDK events: `connectionRequest`, `connected` and `disconnected`. Otherwise no tracking. This helps us to monitor any SDK connection issues. If you wish to disable this, you can do so by setting `ethereumViewModel.enableDebug = false`.


### 4. You can now call any ethereum provider method
### 5. You can now call any ethereum provider method

#### Example 1: Get Chain ID
```kotlin
Expand Down Expand Up @@ -246,5 +329,4 @@ You will need to have MetaMask Mobile wallet installed on your target device i.e
This SDK has an Minimum Android SDK (minSdk) version requirement of 23.

## Resources
Refer to the [MetaMask API Reference](https://docs.metamask.io/wallet/reference/provider-api) for more information.

Refer to the [MetaMask API Reference](https://docs.metamask.io/wallet/reference/provider-api) for more information.
3 changes: 1 addition & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ kotlin {
}

dependencies {

implementation project(path: ':metamask-android-sdk')
implementation project(':metamask-android-sdk')
implementation 'androidx.compose.material:material:1.0.4'
implementation 'com.google.android.material:material:1.9.0'
implementation "androidx.navigation:navigation-compose:2.5.0"
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/java/com/metamask/dapp/DappScreen.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.metamask.dapp

enum class DappScreen(value: String) {
CONNECT("connect"),
ACTIONS("actions"),
SIGN_MESSAGE("sign_message"),
SEND_TRANSACTION("send_transaction"),
SWITCH_CHAIN("switch_chain")
enum class DappScreen {
CONNECT,
ACTIONS,
SIGN_MESSAGE,
SEND_TRANSACTION,
SWITCH_CHAIN
}
4 changes: 3 additions & 1 deletion app/src/main/java/com/metamask/dapp/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.metamask.dapp

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
Expand All @@ -11,7 +12,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.metamask.dapp.ui.theme.MetaMaskAndroidSDKClientTheme
import dagger.hilt.android.AndroidEntryPoint
import io.metamask.androidsdk.EthereumViewModel
import io.metamask.androidsdk.*
import java.util.*

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ buildscript {
classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
}

}// Top-level build file where you can add configuration options common to all sub-projects/modules.
}
plugins {
id 'com.android.application' version '7.3.1' apply false
id 'com.android.library' version '7.3.1' apply false
Expand All @@ -19,4 +19,4 @@ plugins {
}

apply plugin: 'io.github.gradle-nexus.publish-plugin'
apply from: "${rootDir}/scripts/publish-root.gradle"
apply from: "${rootDir}/scripts/publish-auth.gradle"
14 changes: 12 additions & 2 deletions ecies/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,21 @@ android {
}

dependencies {

implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
}

ext {
PUBLISH_GROUP_ID = 'io.metamask.ecies'
PUBLISH_VERSION = '1.0.0'
PUBLISH_ARTIFACT_ID = 'ecies'
}

apply plugin: 'maven-publish'
apply plugin: 'signing'
apply plugin: 'org.jetbrains.dokka'
apply from: "${rootProject.projectDir}/scripts/ecies-publish-module.gradle"
4 changes: 2 additions & 2 deletions metamask-android-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ kotlin {
}

dependencies {
implementation project(':ecies')
implementation 'io.metamask.ecies:ecies:1.0.0'
implementation 'com.google.dagger:hilt-android:2.43.2'
kapt 'com.google.dagger:hilt-compiler:2.43.2'
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
Expand All @@ -70,4 +70,4 @@ ext {
apply plugin: 'maven-publish'
apply plugin: 'signing'
apply plugin: 'org.jetbrains.dokka'
apply from: "${rootProject.projectDir}/scripts/publish-module.gradle"
apply from: "${rootProject.projectDir}/scripts/metamask-android-sdk-publish-module.gradle"
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ internal class CommunicationClient(context: Context, callback: EthereumEventCall
}

private val messageServiceCallback: IMessegeServiceCallback = object : IMessegeServiceCallback.Stub() {
override fun onMessageReceived(message: Bundle) {
val keyExchange = message.getString(KEY_EXCHANGE)
val message = message.getString(MESSAGE)
override fun onMessageReceived(bundle: Bundle) {
val keyExchange = bundle.getString(KEY_EXCHANGE)
val message = bundle.getString(MESSAGE)

if (keyExchange != null) {
handleKeyExchange(keyExchange)
Expand All @@ -89,21 +89,21 @@ internal class CommunicationClient(context: Context, callback: EthereumEventCall
}

fun trackEvent(event: Event, params: MutableMap<String, String>?) {
val params: MutableMap<String, String> = params ?: mutableMapOf(
val parameters: MutableMap<String, String> = params ?: mutableMapOf(
"id" to sessionId
)

when(event) {
Event.CONNECTIONREQUEST -> {
params["commlayer"] = SDKInfo.PLATFORM
params["sdkVersion"] = SDKInfo.VERSION
params["url"] = dapp?.url ?: ""
params["title"] = dapp?.name ?: ""
params["platform"] = SDKInfo.PLATFORM
parameters["commlayer"] = SDKInfo.PLATFORM
parameters["sdkVersion"] = SDKInfo.VERSION
parameters["url"] = dapp?.url ?: ""
parameters["title"] = dapp?.name ?: ""
parameters["platform"] = SDKInfo.PLATFORM
}
else -> Unit
}
tracker.trackEvent(event, params)
tracker.trackEvent(event, parameters)
}

fun setSessionDuration(duration: Long) {
Expand All @@ -118,6 +118,7 @@ internal class CommunicationClient(context: Context, callback: EthereumEventCall

private fun handleMessage(message: String) {
val jsonString = keyExchange.decrypt(message)
Logger.log("CommunicationClient:: Got message: $jsonString")
val json = JSONObject(jsonString)

when (json.optString(MessageType.TYPE.value)) {
Expand Down Expand Up @@ -187,15 +188,27 @@ internal class CommunicationClient(context: Context, callback: EthereumEventCall
}

val request = submittedRequests[id]?.request
Logger.log("CommunicationClient:: Response for request ${request?.method}")
val isResultMethod = EthereumMethod.isResultMethod(request?.method ?: "")

if (!isResultMethod) {
val resultJson = data.optString("result")

if (resultJson.isNotEmpty()) {
val result: Map<String, Any?> = Gson().fromJson(resultJson, object : TypeToken<Map<String, Any?>>() {}.type)
submittedRequests[id]?.callback?.invoke(result)
completeRequest(id, result)
var result: Map<String, Any?>? = Gson().fromJson(resultJson, object : TypeToken<Map<String, Any?>>() {}.type)
if (result != null) {
submittedRequests[id]?.callback?.invoke(result)
completeRequest(id, result)
} else {
val accounts: List<String>? = Gson().fromJson(resultJson, object : TypeToken<List<String>>() {}.type)
Logger.log("CommunicationClient:: Accounts: $accounts")
val account = accounts?.firstOrNull()
if (account != null) {
submittedRequests[id]?.callback?.invoke(account)
completeRequest(id, account)
}
}

} else {
val result: Map<String, Serializable> = Gson().fromJson(data.toString(), object : TypeToken<Map<String, Serializable>>() {}.type)
completeRequest(id, result)
Expand Down Expand Up @@ -275,10 +288,10 @@ internal class CommunicationClient(context: Context, callback: EthereumEventCall
queuedRequests.entries.find { it.value.request.method == EthereumMethod.ETH_REQUEST_ACCOUNTS.value }?.key ?: ""
}

val error: Map<String, Any?> = Gson().fromJson(error, object : TypeToken<Map<String, Any?>>() {}.type)
val errorCode = error["code"] as? Double ?: -1
val errorMap: Map<String, Any?> = Gson().fromJson(error, object : TypeToken<Map<String, Any?>>() {}.type)
val errorCode = errorMap["code"] as? Double ?: -1
val code = errorCode.toInt()
val message = error["message"] as? String ?: ErrorType.message(code)
val message = errorMap["message"] as? String ?: ErrorType.message(code)
completeRequest(requestId, RequestError(code, message))
return true
}
Expand Down Expand Up @@ -355,15 +368,15 @@ internal class CommunicationClient(context: Context, callback: EthereumEventCall
}

private fun sendMessage(message: String) {
val message = Bundle().apply {
val bundle = Bundle().apply {
putString(MESSAGE, message)
}

if (keyExchange.keysExchanged()) {
messageService?.sendMessage(message)
messageService?.sendMessage(bundle)
} else {
Logger.log("CommunicationClient::sendMessage keys not exchanged, queueing job")
queueRequestJob { messageService?.sendMessage(message) }
queueRequestJob { messageService?.sendMessage(bundle) }
}
}

Expand Down Expand Up @@ -469,9 +482,9 @@ internal class CommunicationClient(context: Context, callback: EthereumEventCall

private fun sendKeyExchangeMesage(message: String) {
Logger.log("Sending key exchange $message")
val message = Bundle().apply {
val bundle = Bundle().apply {
putString(KEY_EXCHANGE, message)
}
messageService?.sendMessage(message)
messageService?.sendMessage(bundle)
}
}
Loading

0 comments on commit 912ffd1

Please sign in to comment.