@ -3,14 +3,16 @@ layout: learn
description: Learn about the Android SDK
description: Learn about the Android SDK
permalink: /:collection/:path.html
permalink: /:collection/:path.html
---
---
# Android DApps
# Android DApps
{:.no_toc}
{:.no_toc}
This tutorial is written for readers who are new to either or both Blockstack
This tutorial is written for readers who are new to either or both Blockstack
and Android to create a decentralized application. It contains the following
and Android to create a decentralized application. It contains the following
content:
content:
* TOC
- TOC
{:toc}
{:toc}
This tutorial was extensively tested using Android Studio 3.6 on a Dell XPS 13
This tutorial was extensively tested using Android Studio 3.6 on a Dell XPS 13
@ -76,8 +78,7 @@ If you don't have these installed, take a moment to install or upgrade as needed
## Build the Blockstack hello-world web app
## Build the Blockstack hello-world web app
In this section, you build a Blockstack `hello-world` web application that acts as the companion site to your
In this section, you build a Blockstack `hello-world` web application that acts as the companion site to your Android application.
Android application.
### Generate and launch your hello-blockstack application
### Generate and launch your hello-blockstack application
@ -108,18 +109,16 @@ In this section, you build an initial React.js application called
create netlify.toml
create netlify.toml
create firebase.json
create firebase.json
...
...
added 812 packages from 575 contributors and audited 813 packages in 13.176s
npm WARN ajv-errors@1.0.1 requires a peer of ajv@>=5.0.0 but none is installed. You must install peer dependencies yourself.
found 1 high severity vulnerability
run `npm audit fix` to fix them, or `npm audit` for details
added 840 packages from 582 contributors and audited 843 packages in 18.84s
found 0 vulnerabilities
```
```
Depending on your environment you may have some warnings with the installation. Optionally, you can fix these before continuing to the next section.
Depending on your environment you may have some warnings with the installation. Optionally, you can fix these before continuing to the next section.
```
4. Respond to the prompts to populate the initial app.
4. Depending on your environment, respond to the prompts to populate the initial app.
You might see a prompt similar to the following:
After the process completes successfully, you see a prompt similar to the following:
```bash
```bash
[fsevents] Success:
[fsevents] Success:
@ -128,29 +127,27 @@ In this section, you build an initial React.js application called
You should commit this file. added 1060 packages in 26.901s
You should commit this file. added 1060 packages in 26.901s
```
```
5. R un the initial application.
5. After the initial setup you can now r un the initial application.
```bash
```bash
$ npm run start
$ npm run start
> hello-blockstack@0.0.0 start /Users/user/repos /hello-blockstack
> hello-blockstack-webpack@0.0.0 start /home/user /hello-blockstack
> webpack-dev-server
> webpack-dev-server
Project is running at http://localhost:8080/
ℹ 「wds」: Project is running at http://localhost:9000/
webpack output is served from /
ℹ 「wds」: webpack output is served from /
404s will fallback to /index.html
ℹ 「wds」: Content not from webpack is served from /home/user/hello-blockstack/dist
Hash: 4d2312ba236a4b95dc3a
ℹ 「wdm」: Hash: f5d88efe9c9194f66ddd
Version: webpack 2.7.0
Version: webpack 4.43.0
Time: 2969ms
Time: 2733ms
Built at: 05/19/2020 10:44:50 AM
Asset Size Chunks Chunk Names
Asset Size Chunks Chunk Names
main.js 5.39 MiB main [emitted] main
....
....
Child html-webpack-plugin for "index.html":
[./src/index.js] 1.8 KiB {main} [built]
chunk {0} index.html 541 kB [entry] [rendered]
+ 610 hidden modules
[0] ./~/lodash/lodash.js 540 kB {0} [built]
ℹ 「wdm」: Compiled successfully.
[1] ./~/html-webpack-plugin/lib/loader.js!./src/index.html 533 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
webpack: Compiled successfully.
```
```
The system opens a browser displaying your running application.
The system opens a browser displaying your running application.
@ -168,65 +165,12 @@ In this section, you build an initial React.js application called
7. Follow the prompts appropriate to your situation.
7. Follow the prompts appropriate to your situation.
If you are restoring an existing ID, you may see a prompt about your user
At this point you have only a single application
being nameless, ignore it. At this point you have only a single application
on your test server. So, you should see this single application, with your
on your test server. So, you should see this single application, with your
own `blockstack.id` , once you are signed in:
own `blockstack.id` , once you are signed in:
![](images/running-app.png)
![](images/running-app.png)
### Add a redirect end point to your application
When a user opens the webapp from the Blockstack Browser on an Android phone,
you want the web app to redirect the user to your Android application. The work
you do here will allow it.
1. From the terminal command line, change directory to the root of your sample
application directory.
2. Use the `touch` command to add a redirect endpoint to your application.
This endpoint on the web version of your app will redirect Android users back
to your mobile app.
```bash
$ touch public/redirect.html
```
3. Open `redirect.html` and add code to the endpoint.
```html
<!DOCTYPE html>
< html >
< head >
< title > Hello, Blockstack!< / title >
< script >
function getParameterByName(name) {
var match = RegExp('[?& ]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
var authResponse = getParameterByName('authResponse')
window.location="myblockstackapp:" + authResponse
< / script >
< body >
< / body >
< / html >
```
Blockstack apps are identified by their domain names. The endpoint will
receive a get request with the query parameter `authResponse=XXXX` and
should redirect the browser to `myblockstackapp:XXXX` .
`myblockstackapp:` is custom protocol handler. The handler should be unique
to your application. Your app's web-based authentication uses this handler
to redirect the user back to your Android app. Later, you'll add a reference
to this handler in your Android application.
5. Close and save the `redirect.html` file.
6. Ensure your Blockstack compiles successfully.
## Create the hello-android project
## Create the hello-android project
In this section, you'll create an Android application in Android Studio. You'll
In this section, you'll create an Android application in Android Studio. You'll
@ -237,47 +181,43 @@ run the application in the emulator to test it.
In this section, you create an inital project. You'll validate the application's
In this section, you create an inital project. You'll validate the application's
iniatial state by creating an emulator to run it in. Open Android Studio and do the following:
iniatial state by creating an emulator to run it in. Open Android Studio and do the following:
1. Open Android Studio and choose **Start a new Andriod Studio project** .
1. Open Android Studio and choose **Start a new Andriod Studio project** .
If studio is already started, choose **File > New > New Project** .
If studio is already started, choose **File > New > New Project** .
2. Enter these fields in the **Create Android Project** page.
2. Choose a project template: select **Empty Activity** and press **Next**
3. Enter these fields in the **Create Android Project** page.
< table class = "uk-table" >
< table class = "uk-table" >
< tr >
< tr >
< th > Application Name< / th >
< th > Name< / th >
< td > < code > hello-a ndroid< / code > < / td >
< td > < code > Hello A ndroid< / code > < / td >
< / tr >
< / tr >
< tr >
< tr >
< th > Company domain < / th >
< th > Package name < / th >
< td > < code > < i > USERNAME< / i > .example.com < / code > < / td >
< td > < code > blockstack.id. < i > USERNAME< / i > .hello < / code > < / td >
< / tr >
< / tr >
< tr >
< tr >
< th > Project location< / th >
< th > Project location< / th >
< td > < code > /Users /< i > USERNAME< / i > /AndroidStudioProjects/helloandroid< / code > < / td >
< td > < code > /home /< i > USERNAME< / i > /AndroidStudioProjects/helloandroid< / code > < / td >
< / tr >
< / tr >
< tr >
< tr >
< th > Include Kotlin support< / th >
< th > Language< / th >
< td > Set (checked)< / td >
< td > Select (Kotlin)< / td >
< / tr >
< tr >
< th > Minimum SDK< / th >
< td > Select (API 21: Android 5.0 (Lollipop))< / td >
< / tr >
< / tr >
< / table >
< / table >
3. Press **Next** to display **Target Android Devices** .
4. Check **Phone and Tablet** .
5. Choose API 27: Andriod 8.1 (Oreo) for the target version.
6. Press **Next** .
7. Choose **Empty Activity** and press **Next** .
8. Leave the **Configure Activity** dialog with its defaults.
![](images/configure-activity.png)
![](images/configure-activity.png)
9 . Press **Finish** .
4. Press **Finish** .
Android studio builds your initial project. This can take a bit the first time you do it.
Android studio builds your initial project. This can take a bit the first time you do it.
![](images/initial-build.png)
### Run the app in an emulator
### Run the app in an emulator
In this section, you run the appliation and create an emulator when prompted.
In this section, you run the appliation and create an emulator when prompted.
@ -292,15 +232,15 @@ In this section, you run the appliation and create an emulator when prompted.
Studio prompts you to **Select Hardware** .
Studio prompts you to **Select Hardware** .
4. Choose a Phone running Pixel XL .
4. Choose a Phone device configuration like "Pixel" .
![](images/select-hdw.png)
![](images/select-hdw.png)
Studio prompts you for a system image.
Studio prompts you for a system image.
5. Choose **Oreo** which is API level 27 and press **Next** .
5. Choose **Q** which is API level 29 and press **Next** .
![](images/oreo -api.png)
![](images/q -api.png)
Studio asks you to verify your new emulator configuration.
Studio asks you to verify your new emulator configuration.
@ -310,26 +250,25 @@ In this section, you run the appliation and create an emulator when prompted.
![](images/hello-andriod-1.png)
![](images/hello-andriod-1.png)
### Configure your application with the Blockstack SDK
### Configure your application with the Blockstack SDK
Now that you have created your initial project and verified it running in an emulator, you are ready to begin configuring the application for use with Blockstack.
Now that you have created your initial project and verified it running in an emulator, you are ready to begin configuring the application for use with Blockstack.
1. In studio, open the `AndroidManifest.xml` file.
1. In studio, open the `AndroidManifest.xml` file.
2. Add an `<intent-filter>` with the custom handler for Blockstack.
2. Add an `<intent-filter>` with the custom handler for Blockstack. Replace the host ("flamboyant-darwin-d11c17.netlify.app") with your own url once you have hosted your web app publicly.
```XML
```XML
< intent-filter >
< intent-filter >
< action android:name = "android.intent.action.VIEW" / >
< action android:name = "android.intent.action.VIEW" / >
< category android:name = "android.intent.category.DEFAULT" / >
< category android:name = "android.intent.category.DEFAULT" / >
< category android:name = "android.intent.category.BROWSABLE" / >
< category android:name = "android.intent.category.BROWSABLE" / >
< data android:scheme = "myblockstack app" / >
< data android:scheme = "https" android:host = "flamboyant-darwin-d11c17.netlify. app" / >
< / intent-filter >
< / intent-filter >
```
```
2 . Open the Project's `build.gradle` file.
3 . Open the Project's `build.gradle` file ("Project: Hello Android") .
3 . Add the Jitpack repository `maven { url 'https://jitpack.io' }` to the `repositories` section.
4 . Add the Jitpack repository `maven { url 'https://jitpack.io' }` to the `repositories` section. for all projects
When you finish, that section looks like this:
When you finish, that section looks like this:
@ -343,23 +282,15 @@ Now that you have created your initial project and verified it running in an emu
}
}
```
```
4. Open the Module `build.gradle` file.
5. Open the Module `build.gradle` file ("Module: app").
5. Set the `defaultConfig minSdkVersion` to `19` .
6. Fix a problem with duplicate meta data in the Android SDK: add `packagingOptions`
When you are done, you should see (within your own username not `meepers` ):
```JS
```JS
android {
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.example.meepers.hello_android"
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
...
...
packagingOptions {
exclude 'META-INF/*'
}
}
}
```
```
@ -369,19 +300,22 @@ Now that you have created your initial project and verified it running in an emu
```JS
```JS
dependencies {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.1 '
implementation 'androidx.appcompat:appcompat:1.1.0 '
implementation 'com.android.support.constraint:constraint-layout:1.1.3 '
implementation 'androidx.core:core-ktx:1.2.0 '
implementation 'com.android.support:design:27.1.1 '
implementation 'androidx.constraintlayout:constraintlayout:1.1.3 '
testImplementation 'junit:junit:4.12'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.github.blockstack:blockstack-android:0.4.0'
implementation 'com.github.blockstack:blockstack-android:7940940'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
}
}
```
```
**NOTE** : Ignore the warning on the appcompat` dependencies.
**NOTE** : Ignore the warning on the `junit` dependencies.
8. Sync your project.
8. Sync your project.
@ -391,7 +325,7 @@ Now that you have created your initial project and verified it running in an emu
![](images/sync-success.png)
![](images/sync-success.png)
10 . Run your app in the emulator.
9 . Run your app in the emulator.
You've made a lot of changes, make sure the emulator is still running
You've made a lot of changes, make sure the emulator is still running
correctly.
correctly.
@ -402,48 +336,50 @@ Now that you have created your initial project and verified it running in an emu
The `activity_main.xml` file defines the graphical elements. Some elements are required before you can functionality to your `MainActivity.kt` code.
The `activity_main.xml` file defines the graphical elements. Some elements are required before you can functionality to your `MainActivity.kt` code.
3. Replace the entire content of the file with the following code:
2. Replace the entire content of the file with the following code:
The new interface includes a `BlockstackSignInButton` which is provided by
The new interface includes a `BlockstackSignInButton` which is provided by
the SDK. This SDK includes a themed "Sign in with Blockstack " button
the SDK. This SDK includes a themed "Get Started " button
(`BlockstackSignInButton`). You use this button here with the
(`BlockstackSignInButton`). You use this button here with the
`org.blockstack.android.sdk.ui.BlockstackSignInButton` class.
`org.blockstack.android.sdk.ui.BlockstackSignInButton` class.
```XML
```XML
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
< android.support.constrain t.ConstraintLayout xmlns:android = "http://schemas.android.com/apk/res/android"
< androidx.constraintlayout.widge t.ConstraintLayout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
tools:context=".MainActivity">
tools:context=".MainActivity">
< org.blockstack.android.sdk.ui.BlockstackSignInButton
< org.blockstack.android.sdk.ui.BlockstackSignInButton
android:id="@+id/signInButton"
android:id="@+id/signInButton"
android:layout_width="307dp"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="185dp"
android:layout_marginStart="39dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="16dp" />
app:layout_constraintBottom_toTopOf="@id/userDataTextView" />
< TextView
< TextView
android:id="@+id/userDataTextView"
android:id="@+id/userDataTextView"
android:layout_width="370dp"
android:layout_width="wrap_content"
android:layout_height="27dp"
android:layout_height="wrap_content"
tools:layout_editor_absoluteX="6dp"
android:text="Hello World!"
tools:layout_editor_absoluteY="70dp" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
< / android >
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/signInButton" />
< / androidx.constraintlayout.widget.ConstraintLayout >
```
```
This codes adds a button and some text to your application.
This codes adds a button and some text to your application.
4. Choose **Run > Apply changes** .
3. Choose **Run > Apply changes** .
5. Choose **Run > Run app** in the emulator.
4. Choose **Run > Run app** in the emulator.
The emulator now contains a new interface with a button:
The emulator now contains a new interface with a button:
@ -452,27 +388,35 @@ Now that you have created your initial project and verified it running in an emu
### Add session & authentication code
### Add session & authentication code
1. Open the `MainActivity.kt` file.
1. Open the `MainActivity.kt` file.
2. Add some additional imports to the top below the `android.os.Bundle` import.
2. Add some additional imports to the top, replace the `android.os.Bundle` import.
When you are done, your imports should appear as follows:
When you are done, your imports should appear as follows:
```kotlin
```kotlin
import android.content.Intent
import android.content.Intent
import android.os.Bundle
import android.os.Bundle
import android.support.v7 .app.AppCompatActivity
import androidx.appcompat .app.AppCompatActivity
import android.view.View
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.blockstack.android.sdk.BlockstackSession
import org.blockstack.android.sdk.BlockstackSession
import org.blockstack.android.sdk.Scope
import org.blockstack.android.sdk.BlockstackSignIn
import org.blockstack.android.sdk.UserData
import org.blockstack.android.sdk.SessionStore
import org.blockstack.android.sdk.toBlockstackConfig
import org.blockstack.android.sdk.getBlockstackSharedPreferences
import org.blockstack.android.sdk.model.UserData
import org.blockstack.android.sdk.model.toBlockstackConfig
import org.blockstack.android.sdk.ui.SignInProvider
import org.blockstack.android.sdk.ui.showBlockstackConnect
```
```
3. Add a variable for the Blockstack session before `onCreate` .
3. Add one variable for the Blockstack sign-in flow and one for the Blockstack session that deals with all other function. This needs to be added before `onCreate` .
```kotlin
```kotlin
class MainActivity : AppCompatActivity() {
class MainActivity : AppCompatActivity() {
private var _blockstackSession: BlockstackSession? = null
private lateinit var blockstackSession: BlockstackSession
private lateinit var blockstackSignIn: BlockstackSignIn
override fun onCreate(savedInstanceState: Bundle?) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)
@ -481,42 +425,43 @@ Now that you have created your initial project and verified it running in an emu
}
}
```
```
4. Replace the existing the `onCreate` function with the following:
4. Replace the existing the `onCreate` function with the following, use your own domain if you are already hosting your web app somewhere :
```kotlin
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setContentView(R.layout.activity_main)
val scopes = arrayOf(Scope.StoreWrite)
val appConfig =
val config = "https://flamboyant-darwin-d11c17.netlify.com"
"https://flamboyant-darwin-d11c17.netlify.app".toBlockstackConfig()
.toBlockstackConfig(scopes)
val sessionStore = SessionStore(getBlockstackSharedPreferences())
blockstackSession = BlockstackSession(sessionStore, appConfig)
_blockstackSession = BlockstackSession(this, config)
blockstackSignIn = BlockstackSignIn(sessionStore, appConfig)
BlockstackSignIn.shouldLaunchInCustomTabs = false
signInButton.isEnabled = true
signInButton.setOnClickListener { view: View ->
signInButton.setOnClickListener {
blockstackSession().redirectUserToSignIn {
showBlockstackConnect()
// only called on error
}
}
}
if (intent?.action == Intent.ACTION_VIEW) {
if (intent?.action == Intent.ACTION_VIEW) {
// handle the redirect from sign in
// handle the redirect from sign in
userDataTextView.text = "Signing in now ..."
lifecycleScope.launch(Dispatchers.IO) {
handleAuthResponse(intent)
handleAuthResponse(intent)
}
}
}
}
}
```
```
This new `onCreate` does several things:
This new `onCreate` does several things:
* Define the initial state for the `signInButton` .
- Supply authentication information for connecting to your Blockstack app: `appDomain` (for `scopes` , `redirectURI` , `manifestURI` the default values are used)
* Supply authentication information for connecting to your Blockstack app: `appDomain` and `scopes` (for `redirectURI` , `manifestURI` the default values are used)
- Add a listener for the button click.
* Add a listener for the button click .
- Handles the redirect intent from the sign-in flow .
Notice that the application in this example is a URI you have not set up.
Notice that the application in this example is a URI you have not set up.
Registering and application name takes time, so in time's interest you'll
Registering and application name takes time, so in time's interest you'll
use an existing app that is identical to the `hello-world` you created
use an existing app (https://flamboyant-darwin-d11c17.netlify.app) that is identical to the `hello-world` you created
earlier. For a production version, you'll need to replace `appDomain` ,
earlier. For a production version, you'll need to replace `appDomain` ,
`redirectURI` , `manifestURI` and `scopes` with values appropriate for your
`redirectURI` , `manifestURI` and `scopes` with values appropriate for your
app.
app.
@ -530,155 +475,136 @@ Now that you have created your initial project and verified it running in an emu
}
}
```
```
6. Handle sign in requests with an `onNewIntent` function if the activity was already opened when signing in
6. Create a handler for the authentication response.
Retrieve the authentication token from the custom protocol handler call and
send it to the Blockstack session.
```kotlin
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent?.action == Intent.ACTION_VIEW) {
handleAuthResponse(intent)
}
}
```
7. Create a handler for the authentication response.
```kotlin
```kotlin
private fun handleAuthResponse(intent: Intent) {
private fun handleAuthResponse(intent: Intent) {
val response = intent.dataString
val authResponse = intent.data?.getQueryParameter("authResponse")
if (response != null) {
if (authResponse != null) {
val authResponseTokens = response.split(':')
val userData = blockstackSession.handlePendingSignIn(authResponse)
if (authResponseTokens.size > 1) {
val authResponse = authResponseTokens[1]
blockstackSession().handlePendingSignIn(authResponse, { userData ->
if (userData.hasValue) {
if (userData.hasValue) {
// The user is now signed in!
// The user is now signed in!
runOnUiThread {
runOnUiThread {
onSignIn(userData.value!!)
onSignIn(userData.value!!)
}
}
}
}
})
}
}
}
}
}
```
```
8. Add the convenience method to access the blockstack session.
7. Add `SignInProvider` interface for better user onboarding. Let the activity implement the interface and implement the member function `getBlockstackSignIn`
```kotlin
```kotlin
fun blockstackSession() : BlockstackSession {
class MainActivity : AppCompatActivity(), SignInProvider {
val session = _blockstackSession
...
if(session != null) {
return session
override fun provideBlockstackSignIn(): BlockstackSignIn {
} else {
return blockstackSignIn
throw IllegalStateException("No session.")
}
}
}
}
```
```
9 . Verify your final `MainActivity.kt` code looks like this:
8 . Verify your final `MainActivity.kt` code looks like this:
```kotlin
```kotlin
class MainActivity : AppCompatActivity() {
package blockstack.id.user.hello
```
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.\*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.blockstack.android.sdk.BlockstackSession
import org.blockstack.android.sdk.BlockstackSignIn
import org.blockstack.android.sdk.SessionStore
import org.blockstack.android.sdk.getBlockstackSharedPreferences
import org.blockstack.android.sdk.model.UserData
import org.blockstack.android.sdk.model.toBlockstackConfig
import org.blockstack.android.sdk.ui.SignInProvider
import org.blockstack.android.sdk.ui.showBlockstackConnect
class MainActivity : AppCompatActivity(), SignInProvider {
private var _blockstackSession: BlockstackSession? = null
private lateinit var blockstackSession: BlockstackSession
private lateinit var blockstackSignIn: BlockstackSignIn
override fun onCreate(savedInstanceState: Bundle?) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setContentView(R.layout.activity_main)
signInButton.isEnabled = false
val appConfig =
"https://flamboyant-darwin-d11c17.netlify.app".toBlockstackConfig()
val scopes = arrayOf(Scope.StoreWrite)
val sessionStore = SessionStore(getBlockstackSharedPreferences())
val config = "https://flamboyant-darwin-d11c17.netlify.com"
blockstackSession = BlockstackSession(sessionStore, appConfig)
.toBlockstackConfig(scopes)
blockstackSignIn = BlockstackSignIn(sessionStore, appConfig)
BlockstackSignIn.shouldLaunchInCustomTabs = false
_blockstackSession = BlockstackSession(this, config)
signInButton.isEnabled = true
signInButton.setOnClickListener { view: View ->
signInButton.setOnClickListener {
blockstackSession().redirectUserToSignIn {
showBlockstackConnect()
// only called on error
}
}
}
if (intent?.action == Intent.ACTION_VIEW) {
if (intent?.action == Intent.ACTION_VIEW) {
// handle the redirect from sign in
userDataTextView.text = "Signing in now ..."
lifecycleScope.launch(Dispatchers.IO) {
handleAuthResponse(intent)
handleAuthResponse(intent)
}
}
}
}
}
private fun onSignIn(userData: UserData) {
private fun onSignIn(userData: UserData) {
userDataTextView.text = "Signed in as ${userData.decentralizedID}"
userDataTextView.text = "Signed in as ${userData.decentralizedID}"
signInButton.isEnabled = false
signInButton.isEnabled = false
}
}
override fun onNewIntent(intent: Intent?) {
private suspend fun handleAuthResponse(intent: Intent) {
super.onNewIntent(intent)
val authResponse = intent.data?.getQueryParameter("authResponse")
if (authResponse != null) {
if (intent?.action == Intent.ACTION_VIEW) {
val userData = blockstackSession.handlePendingSignIn(authResponse)
handleAuthResponse(intent)
}
}
private fun handleAuthResponse(intent: Intent) {
val response = intent.dataString
if (response != null) {
val authResponseTokens = response.split(':')
if (authResponseTokens.size > 1) {
val authResponse = authResponseTokens[1]
blockstackSession().handlePendingSignIn(authResponse, { userData ->
if (userData.hasValue) {
if (userData.hasValue) {
// The user is now signed in!
// The user is now signed in!
runOnUiThread {
runOnUiThread {
onSignIn(userData.value!!)
onSignIn(userData.value!!)
}
}
}
}
})
}
}
}
}
}
fun blockstackSession() : BlockstackSession {
override fun provideBlockstackSignIn(): BlockstackSignIn {
val session = _blockstackSession
return blockstackSignIn
if(session != null) {
return session
} else {
throw IllegalStateException("No session.")
}
}
}
}
}
```
```
### Run the final app in the emulator
### Run the final app in the emulator
1. Choose **Run > Apply changes** .
1. Choose **Run > Apply changes** .
2. Choose **Run > Run app** in the emulator.
2. Choose **Run > Run app** in the emulator.
3. When you see the application open, choose **Sign in with Blockstack** .
3. When you see the application open, choose **Get Started** .
4. A small information is presented about the sign-in flow
The system prompts you how to open.
![](images/chrome-prompt .png)
![](images/connect-ui .png)
4. Choose **Chrome** and click **ALWAYS** .
5. Select **Get Started**
5. Move through the rest of the Chrome prompts .
The system might prompt you how to select a browser .
The system presents you with your final application.
6. Work through the Blockstack prompts to login.
7. Blockstack redirects you to a web site. Open it with your Android app: Select **Hello Android** and **Always**
![](images/final-app .png)
![](images/connect-response .png)
6. Work through the Blockstack prompts to log in.
8. The screen after the sign-in flow shows the owner address of the username that was entered during sign- in.
![](images/final-app.png)
## Where to go next
## Where to go next
Congratulations, you've completed your Android app using the Blockstack Android SDK.
Congratulations, you've completed your Android app using the Blockstack Android SDK.
Learn more about Blockstack by [trying another tutorial ](https://blockstack.org/tutorials ).
Learn more about Blockstack by [trying another tutorial ](https://blockstack.org/tutorials ).
```