diff --git a/.gitignore b/.gitignore index 903b4536..809a3161 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,3 @@ -# downstream content -_core -_browser -_android -_ios -_gaia - - # OS or Editor folders .DS_Store node_modules @@ -14,3 +6,5 @@ node_modules _site .sass-cache .jekyll-metadata +package-lock.json +package.json diff --git a/_android/.svn/entries b/_android/.svn/entries new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/_android/.svn/entries @@ -0,0 +1 @@ +12 diff --git a/_android/.svn/format b/_android/.svn/format new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/_android/.svn/format @@ -0,0 +1 @@ +12 diff --git a/_android/.svn/pristine/14/1495dab64473f038310e6601ebb6f0450c97a2af.svn-base b/_android/.svn/pristine/14/1495dab64473f038310e6601ebb6f0450c97a2af.svn-base new file mode 100644 index 00000000..2eaccb4f Binary files /dev/null and b/_android/.svn/pristine/14/1495dab64473f038310e6601ebb6f0450c97a2af.svn-base differ diff --git a/_android/.svn/pristine/1e/1e84e69d0aeae9c31e35f2ba6dad3de414550ebf.svn-base b/_android/.svn/pristine/1e/1e84e69d0aeae9c31e35f2ba6dad3de414550ebf.svn-base new file mode 100644 index 00000000..1be7edf5 Binary files /dev/null and b/_android/.svn/pristine/1e/1e84e69d0aeae9c31e35f2ba6dad3de414550ebf.svn-base differ diff --git a/_android/.svn/pristine/2c/2c518a2d8710e880cc0fb87c202979c15c2b4cbe.svn-base b/_android/.svn/pristine/2c/2c518a2d8710e880cc0fb87c202979c15c2b4cbe.svn-base new file mode 100644 index 00000000..b5e5c141 Binary files /dev/null and b/_android/.svn/pristine/2c/2c518a2d8710e880cc0fb87c202979c15c2b4cbe.svn-base differ diff --git a/_android/.svn/pristine/41/410814802457e751ef97090c0813861c8e2234c9.svn-base b/_android/.svn/pristine/41/410814802457e751ef97090c0813861c8e2234c9.svn-base new file mode 100644 index 00000000..081d5050 Binary files /dev/null and b/_android/.svn/pristine/41/410814802457e751ef97090c0813861c8e2234c9.svn-base differ diff --git a/_android/.svn/pristine/53/53c6a58a4107359c52b61f15feda85eaea9fba81.svn-base b/_android/.svn/pristine/53/53c6a58a4107359c52b61f15feda85eaea9fba81.svn-base new file mode 100644 index 00000000..1de35691 Binary files /dev/null and b/_android/.svn/pristine/53/53c6a58a4107359c52b61f15feda85eaea9fba81.svn-base differ diff --git a/_android/.svn/pristine/5f/5fb343bd86c0ea238c08217aaa064a1d2cb08707.svn-base b/_android/.svn/pristine/5f/5fb343bd86c0ea238c08217aaa064a1d2cb08707.svn-base new file mode 100644 index 00000000..62ae3f5d Binary files /dev/null and b/_android/.svn/pristine/5f/5fb343bd86c0ea238c08217aaa064a1d2cb08707.svn-base differ diff --git a/_android/.svn/pristine/6b/6bbb57e8973ee164a4f7dfb71fe008ad2b0776b3.svn-base b/_android/.svn/pristine/6b/6bbb57e8973ee164a4f7dfb71fe008ad2b0776b3.svn-base new file mode 100644 index 00000000..914b26e5 Binary files /dev/null and b/_android/.svn/pristine/6b/6bbb57e8973ee164a4f7dfb71fe008ad2b0776b3.svn-base differ diff --git a/_android/.svn/pristine/75/75758e4df03bd71c064433719414818a69d19709.svn-base b/_android/.svn/pristine/75/75758e4df03bd71c064433719414818a69d19709.svn-base new file mode 100644 index 00000000..5e4d6256 Binary files /dev/null and b/_android/.svn/pristine/75/75758e4df03bd71c064433719414818a69d19709.svn-base differ diff --git a/_android/.svn/pristine/83/832a38b5a0091b01fd469a28cd5c7299ed0895dc.svn-base b/_android/.svn/pristine/83/832a38b5a0091b01fd469a28cd5c7299ed0895dc.svn-base new file mode 100644 index 00000000..601f3e8a Binary files /dev/null and b/_android/.svn/pristine/83/832a38b5a0091b01fd469a28cd5c7299ed0895dc.svn-base differ diff --git a/_android/.svn/pristine/85/85768bb09fc031d0d5770a7bab301dc61617ce8f.svn-base b/_android/.svn/pristine/85/85768bb09fc031d0d5770a7bab301dc61617ce8f.svn-base new file mode 100644 index 00000000..d434f9bb Binary files /dev/null and b/_android/.svn/pristine/85/85768bb09fc031d0d5770a7bab301dc61617ce8f.svn-base differ diff --git a/_android/.svn/pristine/a1/a10d2160fb036c58a0e7e171b9ff8fd9652d3c06.svn-base b/_android/.svn/pristine/a1/a10d2160fb036c58a0e7e171b9ff8fd9652d3c06.svn-base new file mode 100644 index 00000000..484d24fe --- /dev/null +++ b/_android/.svn/pristine/a1/a10d2160fb036c58a0e7e171b9ff8fd9652d3c06.svn-base @@ -0,0 +1,773 @@ +--- +layout: learn +permalink: /:collection/:path.html +--- +# Android SDK Tutorial (Pre-release) +{:.no_toc} + +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 +content: + +* TOC +{:toc} + +This tutorial was extensively tested using Android Studio 3.1 on a MacBook Air +running High Sierra 10.13.4. If your environment is different, you may encounter +slight or even major discrepancies when performing the procedures in this +tutorial. Please [join the Blockstack community +Slack](https://slofile.com/slack/blockstack) and post questions or comments to +the `#support` channel. + +Finally, this tutorial is written for all levels from the beginner to the most +experienced. For best results, beginners should follow the guide as written. It +is expected that the fast or furiously brilliant will skip ahead and improvise +on this material at will. Fair journey one and all. + +If you prefer, you can skip working through the tutorial all together. Instead, +you can [download the final project code](images/helloandroid.zip) and import it +into Android Studio to review it. + +## Understand the sample application flow + +When complete, the sample application is a simple `hello-world` display. It is +intended for user on an Android phone. + +![](images/final-app.png) + +Only users with an existing `blockstack.id` can run your +final sample application. When complete, users interact with the sample +application by doing the following: + +![](images/app-flow.png) + +## Set up your environment + +This sample application has two code bases, a Blockstack `hello-blockstack` +application and a `hello-andriod` Android application. Before you start +developing the sample, there are a few elements you need in your environment. + +### Install Android Studio + +If you are an experienced Android developer and already have an Android +development environment on your workstation, you can use that and skip this +step. However, you will need to adjust the remaining instructions for your +environment. + +Follow the installation instructions to download and [Android Studio +3.1](https://developer.android.com/studio/install) for your operating system. +Depending on your network connection, this can take between 15-30 minutes. + +![](images/studio-download.png) + +### Do you have npm? + +The Blockstack code in this tutorial relies on the `npm` dependency manager. +Before you begin, verify you have installed `npm` using the `which` command to +verify. + +```bash +$ which npm +/usr/local/bin/npm +``` + +If you don't find `npm` in your system, [install +it](https://www.npmjs.com/get-npm). + +### Install the Blockstack test rig + +Users interact with Blockstack-enabled applications through a web browser. You +can Blockstack in test mode, on `localhost` or you can interact with completed +apps through the Blockstack webapp which is available at +[https://browser.blockstack.org/]. + +If you have already installed Blockstack for testing locally and have an +existing Blockstack ID, skip this section. Otherwise, continue onto install +Blockstack. + +1. Go to [Blockstack](https://blockstack.org/install) + + ![](images/blockstack-install.png) + +2. Install the version appropriate for your operating system. + + +### Use npm to install Yeoman and the Blockstack App Generator + +You use `npm` to install Yeoman. Yeoman is a generic scaffolding system that +helps users rapidly start new projects and streamline the maintenance of +existing projects. + + +1. Install Yeoman. + + ```bash + npm install -g yo + ``` +2. Install the Blockstack application generator. + + ```bash + npm install -g generator-blockstack + ``` + + +## Build the Blockstack hello-world + +In this section, you build a Blockstack `hello-world` application. Then, you +modify the `hello-world` to interact with the Android app via a redirect. + +### Generate and launch your hello-blockstack application + +In this section, you build an initial React.js application called +`hello-blockstack`. + +1. Create a `hello-blockstack` directory. + + ```bash + mkdir hello-blockstack + ``` + +2. Change into your new directory. + + ```bash + cd hello-blockstack + ``` + +3. Use Yeoman and the Blockstack application generator to create your initial `hello-blockstack` application. + + ```bash + yo blockstack:react + ``` + + You should see several interactive prompts. + + ```bash + $ yo blockstack:react + ========================================================================== + We are constantly looking for ways to make yo better! + May we anonymously report usage statistics to improve the tool over time? + More info: https://github.com/yeoman/insight & http://yeoman.io + ========================================================================== No + + _-----_ ╭──────────────────────────╮ + | | │ Welcome to the │ + |--(o)--| │ Blockstack app │ + --------- │ generator! │ + ( _U_ ) ╰──────────────────────────╯ + /___A___\ / + | ~ | + __'.___.'__ + |° Y + + ? Are you ready to build a Blockstack app in React? (Y/n) + ``` + +4. Respond to the prompts to populate the initial app. + + After the process completes successfully, you see a prompt similar to the following: + + ```bash + [fsevents] Success: + "/Users/theuser/repos/hello-blockstack/node_modules/fsevents/lib/binding/Release/node-v59-darwin-x64/fse.node" + is installed via remote npm notice created a lockfile as package-lock.json. + You should commit this file. added 1060 packages in 26.901s + ``` + +5. Run the initial application. + + ```bash + $ npm start + + > hello-blockstack@0.0.0 start /Users/moxiegirl/repos/hello-blockstack + > webpack-dev-server + + Project is running at http://localhost:8080/ + webpack output is served from / + 404s will fallback to /index.html + Hash: 4d2312ba236a4b95dc3a + Version: webpack 2.7.0 + Time: 2969ms + Asset Size Chunks Chunk Names + .... + Child html-webpack-plugin for "index.html": + chunk {0} index.html 541 kB [entry] [rendered] + [0] ./~/lodash/lodash.js 540 kB {0} [built] + [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. + + ![](images/blockstack-signin.png) + + At this point, the browser is running a Blockstack server on your local host. + This is for testing your applications only. + +6. Choose **Sign in with Blockstack** + + The system displays a prompt allowing you to create a new Blockstack ID or restore an existing one. + + ![](images/create-restore.png) + +7. Follow the prompts appropriate to your situation. + + If you are restoring an existing ID, you may see a prompt about your user + 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 + own `blockstack.id` display name, once you are signed in: + + ![](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 + + + + Hello, Blockstack! + + + + + ``` + + 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 + +In this section, you'll create an Android application in Android Studio. You'll +run the application in the emulator to test it. + +### Create a simple project + +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: + + +1. Open Android Studio and choose **Start a new Andriod Studio project**. + + If studio is already started, choose **File > New > New Project**. + +2. Enter these fields in the **Create Android Project** page. + + + + + + + + + + + + + + + + + + +
Application Namehello-android
Company domainUSERNAME.example.com
Project location/Users/USERNAME/AndroidStudioProjects/helloandroid
Include Kotlin supportSet (checked)
+ +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) + +9. Press **Finish**. + + 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 + +In this section, you run the appliation and create an emulator when prompted. + +1. Once the project is imported into studio, click the `app` module in the **Project** window. + +2. Then, select **Run > Run** (or click the green arrow in the toolbar). + + Studio prompts you to **Select Deployment Target**. + +3. Choose **Create New Virtual Device** and press **OK**. + + Studio prompts you to **Select Hardware**. + +4. Choose a Phone running Pixel XL. + + ![](images/select-hdw.png) + + Studio prompts you for a system image. + +5. Choose **Oreo** which is API level 27 and press **Next**. + + ![](images/oreo-api.png) + + Studio asks you to verify your new emulator configuration. + +6. Press **Finish**. + + The emulation takes a moment to build. Then, studio launches the emulation and opens your application. + + ![](images/hello-andriod-1.png) + + +### 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. + +1. In studio, open the `AndroidManifest.xml` file. +2. Add the a `launchMode` to the `.MainActivity` definition. + + ```XML + + ``` + + Blockstack requires that the activity that starts the sign-in process also + handles the auth reponse token. This means that the activity needs to run in + `singleTask` launch mode. + +2. Add an `` with the custom handler for Blockstack. + + ```XML + + + + + + + ``` + +2. Open the Project's `build.gradle` file. +3. Add the Jitpack repository `maven { url 'https://jitpack.io' }` to the `repositories` section. + + When you finish, that section looks like this: + + ```JS + allprojects { + repositories { + google() + jcenter() + maven { url 'https://jitpack.io' } + } + } + ``` + +4. Open the Module `build.gradle` file. +5. Set the `defaultConfig minSdkVersion` to `19`. + + When you are done, you should see (within your own username not `moxiegirl`): + + ```JS + android { + compileSdkVersion 27 + defaultConfig { + applicationId "com.example.moxiegirl.hello_android" + minSdkVersion 19 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + ... + } + ``` + +7. Below this, add the Blockstack Android SDK dependency to your project's `dependencies` list: + + When you are done you should see: + + ```JS + dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:27.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + implementation 'com.github.blockstack:blockstack-android:0.3.0' + } + + ``` + + **NOTE**: Ignore the warning on the appcompat` dependencies. + +8. Sync your project. + + ![](images/sync-project.png) + + Be sure to check the sync completed successfully. + + ![](images/sync-success.png) + +10. Run your app in the emulator. + + You've made a lot of changes, make sure the emulator is still running + correctly. + +### Add a simple interface + +1. Open the `app/res/layout/activity_main.xml` file. + + 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: + + The new interface includes a `BlockstackSignInButton` which is provided by + the SDK. This SDK includes a themed "Sign in with Blockstack" button + (`BlockstackSignInButton`). You use this button in your here with the + `org.blockstack.android.sdk.ui.BlockstackSignInButton` class. + + ```XML + + + + + + + + Apply changes**. + +5. Choose **Run > Run app** in the emulator. + + The emulator now contains a new interface with a button: + + ![](images/new-interface.png) + +### Add session & authentication code + +1. Open the `MainActivity.kt` file. +2. Add some additional imports to the top below the `android.os.Bundle` import. + + When you are done, your imports should appear as follows: + + ```kotlin + + import android.support.v7.app.AppCompatActivity + import android.os.Bundle + + import android.support.v7.app.AppCompatActivity + import android.view.View + import kotlinx.android.synthetic.main.activity_main.* + import org.blockstack.android.sdk.BlockstackSession + import org.blockstack.android.sdk.Scope + import org.blockstack.android.sdk.UserData + import java.net.URI + ``` +3. Add a variable for the Blockstack session before `onCreate`. + + ```kotlin + class MainActivity : AppCompatActivity() { + + private var _blockstackSession: BlockstackSession? = null + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + } + } + ``` + +4. Replace the existing the `onCreate` function with the following: + + ```kotlin + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + signInButton.isEnabled = false + + val appDomain = URI("https://flamboyant-darwin-d11c17.netlify.com") + val redirectURI = URI("${appDomain}/redirect") + val manifestURI = URI("${appDomain}/manifest.json") + val scopes = arrayOf(Scope.StoreWrite) + + val config = java.net.URI("https://flamboyant-darwin-d11c17.netlify.com").run { + org.blockstack.android.sdk.BlockstackConfig( + this, + redirectURI, + manifestURI, + scopes + } + + _blockstackSession = BlockstackSession(this, config, + onLoadedCallback = { + signInButton.isEnabled = true + }) + + + signInButton.setOnClickListener { view: View -> + blockstackSession().redirectUserToSignIn { userData -> + if (userData.hasValue) { + runOnUiThread { + onSignIn(userData.value!!) + } + } + } + } + if (intent?.action == Intent.ACTION_VIEW) { + // handle the redirect from sign in + handleAuthResponse(intent) + } + } + ``` + + This new `onCreate` does several things: + + * Define the initial state for the `signInButton`. + * Supply authentication information for connecting to your Blockstack app: `appDomain`, `redirectURI`, `manifestURI` and `scopes` + * Add a listener for the button click. + + 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 + use an existing app that is identical to the `hello-world` you created + earlier. For a produciton verison, you'll need to replace `appDomain`, + `redirectURI`, `manifestURI` and `scopes` with values appropriate for your + app. + +5. Add a private function to reflect when a user successfully signs in. + + ```kotlin + private fun onSignIn(userData: UserData) { + userDataTextView.text = "Signed in as ${userData.decentralizedID}" + + signInButton.isEnabled = false + + } + ``` + +6. Handle sign in requests with an `onNewIntent` function if the activity was already opened when signing in + + 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 + 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) { + // The user is now signed in! + runOnUiThread { + onSignIn(userData.value!!) + } + } + }) + } + } + } + ``` + +8. Add the convenience method to access the blockstack session. + + ```kotlin + fun blockstackSession() : BlockstackSession { + val session = _blockstackSession + if(session != null) { + return session + } else { + throw IllegalStateException("No session.") + } + } + ``` + +9. Verify your final `MainActivity.kt` code looks like this: + + ```kotlin + class MainActivity : AppCompatActivity() { + + private var _blockstackSession: BlockstackSession? = null + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + signInButton.isEnabled = false + + val appDomain = URI("https://flamboyant-darwin-d11c17.netlify.com") + val redirectURI = URI("${appDomain}/redirect") + val manifestURI = URI("${appDomain}/manifest.json") + val scopes = arrayOf(Scope.StoreWrite) + + _blockstackSession = BlockstackSession(this, appDomain, redirectURI, manifestURI, scopes, + onLoadedCallback = {signInButton.isEnabled = true + }) + + + signInButton.setOnClickListener { view: View -> + blockstackSession().redirectUserToSignIn { userData -> + if (userData.hasValue) { + runOnUiThread { + onSignIn(userData) + } + } + } + } + if (intent?.action == Intent.ACTION_VIEW) { + handleAuthResponse(intent) + } + } + + private fun onSignIn(userData: UserData) { + userDataTextView.text = "Signed in as ${userData.decentralizedID}" + + signInButton.isEnabled = false + + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + + if (intent?.action == Intent.ACTION_VIEW) { + 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) { + // The user is now signed in! + runOnUiThread { + onSignIn(userData.value!!) + } + } + }) + } + } + } + + fun blockstackSession() : BlockstackSession { + val session = _blockstackSession + if(session != null) { + return session + } else { + throw IllegalStateException("No session.") + } + } + + + } + ``` + +### Run the final app in the emulator + +1. Choose **Run > Apply changes**. +2. Choose **Run > Run app** in the emulator. +3. When you see the application open, choose **Sign in with Blockstack**. + + The system prompts you how to open. + + ![](images/chrome-prompt.png) + +4. Choose **Chrome** and click **ALWAYS**. +5. Move through the rest of the Chrome prompts. + + The system presents you with your final application. + + ![](images/final-app.png) + +6. Work through the Blockstack prompts to login. + + +## Where to go next + +Congratulations, you've completed your Android app using the new, pre-release +Blockstack Android SDK. Thank you for trying this pre-release. Please let us +know about your experience by tweeting to +[@blockstack](https://twitter.com/blockstack). + +Learn more about Blockstack by [trying another tutorial](https://blockstack.org/tutorials). diff --git a/_android/.svn/pristine/b4/b4b6120a031d86c0b31735cda730ff4fc613167b.svn-base b/_android/.svn/pristine/b4/b4b6120a031d86c0b31735cda730ff4fc613167b.svn-base new file mode 100644 index 00000000..c3680a2d Binary files /dev/null and b/_android/.svn/pristine/b4/b4b6120a031d86c0b31735cda730ff4fc613167b.svn-base differ diff --git a/_android/.svn/pristine/c5/c5cb2871cb79946a062445b18a242ca41c9cb789.svn-base b/_android/.svn/pristine/c5/c5cb2871cb79946a062445b18a242ca41c9cb789.svn-base new file mode 100644 index 00000000..8dc73142 Binary files /dev/null and b/_android/.svn/pristine/c5/c5cb2871cb79946a062445b18a242ca41c9cb789.svn-base differ diff --git a/_android/.svn/pristine/e8/e818024be7864ccee3a60629bb6e02c269eb1b86.svn-base b/_android/.svn/pristine/e8/e818024be7864ccee3a60629bb6e02c269eb1b86.svn-base new file mode 100644 index 00000000..f60822ab Binary files /dev/null and b/_android/.svn/pristine/e8/e818024be7864ccee3a60629bb6e02c269eb1b86.svn-base differ diff --git a/_android/.svn/pristine/ec/ec28305cabded3a21d65ddbc0e1aa5fc446567d3.svn-base b/_android/.svn/pristine/ec/ec28305cabded3a21d65ddbc0e1aa5fc446567d3.svn-base new file mode 100644 index 00000000..fa8b85a3 Binary files /dev/null and b/_android/.svn/pristine/ec/ec28305cabded3a21d65ddbc0e1aa5fc446567d3.svn-base differ diff --git a/_android/.svn/pristine/f4/f46b7546eae669225bf3d9339962bd87f7a063d0.svn-base b/_android/.svn/pristine/f4/f46b7546eae669225bf3d9339962bd87f7a063d0.svn-base new file mode 100644 index 00000000..9838c05f Binary files /dev/null and b/_android/.svn/pristine/f4/f46b7546eae669225bf3d9339962bd87f7a063d0.svn-base differ diff --git a/_android/.svn/pristine/fb/fb8ec93eaf3886ffae25b002fc76cba129f3b65a.svn-base b/_android/.svn/pristine/fb/fb8ec93eaf3886ffae25b002fc76cba129f3b65a.svn-base new file mode 100644 index 00000000..01f62b83 Binary files /dev/null and b/_android/.svn/pristine/fb/fb8ec93eaf3886ffae25b002fc76cba129f3b65a.svn-base differ diff --git a/_android/.svn/wc.db b/_android/.svn/wc.db new file mode 100644 index 00000000..f32d1b18 Binary files /dev/null and b/_android/.svn/wc.db differ diff --git a/_android/.svn/wc.db-journal b/_android/.svn/wc.db-journal new file mode 100644 index 00000000..e69de29b diff --git a/_android/images/app-flow.png b/_android/images/app-flow.png new file mode 100644 index 00000000..fa8b85a3 Binary files /dev/null and b/_android/images/app-flow.png differ diff --git a/_android/images/blockstack-install.png b/_android/images/blockstack-install.png new file mode 100644 index 00000000..5e4d6256 Binary files /dev/null and b/_android/images/blockstack-install.png differ diff --git a/_android/images/blockstack-signin.png b/_android/images/blockstack-signin.png new file mode 100644 index 00000000..081d5050 Binary files /dev/null and b/_android/images/blockstack-signin.png differ diff --git a/_android/images/chrome-prompt.png b/_android/images/chrome-prompt.png new file mode 100644 index 00000000..f60822ab Binary files /dev/null and b/_android/images/chrome-prompt.png differ diff --git a/_android/images/configure-activity.png b/_android/images/configure-activity.png new file mode 100644 index 00000000..1be7edf5 Binary files /dev/null and b/_android/images/configure-activity.png differ diff --git a/_android/images/create-restore.png b/_android/images/create-restore.png new file mode 100644 index 00000000..914b26e5 Binary files /dev/null and b/_android/images/create-restore.png differ diff --git a/_android/images/final-app.png b/_android/images/final-app.png new file mode 100644 index 00000000..01f62b83 Binary files /dev/null and b/_android/images/final-app.png differ diff --git a/_android/images/hello-andriod-1.png b/_android/images/hello-andriod-1.png new file mode 100644 index 00000000..c3680a2d Binary files /dev/null and b/_android/images/hello-andriod-1.png differ diff --git a/_android/images/helloandroid.zip b/_android/images/helloandroid.zip new file mode 100644 index 00000000..672ab7e0 Binary files /dev/null and b/_android/images/helloandroid.zip differ diff --git a/_android/images/initial-build.png b/_android/images/initial-build.png new file mode 100644 index 00000000..601f3e8a Binary files /dev/null and b/_android/images/initial-build.png differ diff --git a/_android/images/new-interface.png b/_android/images/new-interface.png new file mode 100644 index 00000000..d434f9bb Binary files /dev/null and b/_android/images/new-interface.png differ diff --git a/_android/images/oreo-api.png b/_android/images/oreo-api.png new file mode 100644 index 00000000..1de35691 Binary files /dev/null and b/_android/images/oreo-api.png differ diff --git a/_android/images/running-app.png b/_android/images/running-app.png new file mode 100644 index 00000000..9838c05f Binary files /dev/null and b/_android/images/running-app.png differ diff --git a/_android/images/select-hdw.png b/_android/images/select-hdw.png new file mode 100644 index 00000000..2eaccb4f Binary files /dev/null and b/_android/images/select-hdw.png differ diff --git a/_android/images/studio-download.png b/_android/images/studio-download.png new file mode 100644 index 00000000..8dc73142 Binary files /dev/null and b/_android/images/studio-download.png differ diff --git a/_android/images/sync-project.png b/_android/images/sync-project.png new file mode 100644 index 00000000..b5e5c141 Binary files /dev/null and b/_android/images/sync-project.png differ diff --git a/_android/images/sync-success.png b/_android/images/sync-success.png new file mode 100644 index 00000000..62ae3f5d Binary files /dev/null and b/_android/images/sync-success.png differ diff --git a/_android/tutorial.md b/_android/tutorial.md new file mode 100644 index 00000000..73af907a --- /dev/null +++ b/_android/tutorial.md @@ -0,0 +1,732 @@ +--- +layout: learn +permalink: /:collection/:path.html +--- +# Android SDK Tutorial (Pre-release) +{:.no_toc} + +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 +content: + +* TOC +{:toc} + +This tutorial was extensively tested using Android Studio 3.1 on a MacBook Air +running High Sierra 10.13.4. If your environment is different, you may encounter +slight or even major discrepancies when performing the procedures in this +tutorial. Please [join the Blockstack community +Slack](https://slofile.com/slack/blockstack) and post questions or comments to +the `#support` channel. + +Finally, this tutorial is written for all levels from the beginner to the most +experienced. For best results, beginners should follow the guide as written. It +is expected that the fast or furiously brilliant will skip ahead and improvise +on this material at will. Fair journey one and all. + +If you prefer, you can skip working through the tutorial all together. Instead, +you can [download the final project code](images/helloandroid.zip) and import it +into Android Studio to review it. + +## Understand the sample application flow + +When complete, the sample application is a simple `hello-world` display. It is +intended for user on an Android phone. + +![](images/final-app.png) + +Only users with an existing `blockstack.id` can run your +final sample application. When complete, users interact with the sample +application by doing the following: + +![](images/app-flow.png) + +## Set up your environment + +This sample application has two code bases, a Blockstack `hello-blockstack` +application and a `hello-andriod` Android application. Before you start +developing the sample, there are a few elements you need in your environment. + +### Install Android Studio + +If you are an experienced Android developer and already have an Android +development environment on your workstation, you can use that and skip this +step. However, you will need to adjust the remaining instructions for your +environment. + +Follow the installation instructions to download and [Android Studio +3.1](https://developer.android.com/studio/install) for your operating system. +Depending on your network connection, this can take between 15-30 minutes. + +![](images/studio-download.png) + +### Do you have npm? + +The Blockstack code in this tutorial relies on the `npm` dependency manager. +Before you begin, verify you have installed `npm` using the `which` command to +verify. + +```bash +$ which npm +/usr/local/bin/npm +``` + +If you don't find `npm` in your system, [install +it](https://www.npmjs.com/get-npm). + +### Install the Blockstack test rig + +Users interact with Blockstack-enabled applications through a web browser. You +can Blockstack in test mode, on `localhost` or you can interact with completed +apps through the Blockstack webapp which is available at +[https://browser.blockstack.org/]. + +If you have already installed Blockstack for testing locally and have an +existing Blockstack ID, skip this section. Otherwise, continue onto install +Blockstack. + +1. Go to [Blockstack](https://blockstack.org/install) + + ![](images/blockstack-install.png) + +2. Install the version appropriate for your operating system. + + +### Use npm to install Yeoman and the Blockstack App Generator + +You use `npm` to install Yeoman. Yeoman is a generic scaffolding system that +helps users rapidly start new projects and streamline the maintenance of +existing projects. + + +1. Install Yeoman. + + ```bash + npm install -g yo + ``` +2. Install the Blockstack application generator. + + ```bash + npm install -g generator-blockstack + ``` + + +## Build the Blockstack hello-world + +In this section, you build a Blockstack `hello-world` application. Then, you +modify the `hello-world` to interact with the Android app via a redirect. + +### Generate and launch your hello-blockstack application + +In this section, you build an initial React.js application called +`hello-blockstack`. + +1. Create a `hello-blockstack` directory. + + ```bash + mkdir hello-blockstack + ``` + +2. Change into your new directory. + + ```bash + cd hello-blockstack + ``` + +3. Use Yeoman and the Blockstack application generator to create your initial `hello-blockstack` application. + + ```bash + yo blockstack:react + ``` + + You should see several interactive prompts. + + ```bash + $ yo blockstack:react + ========================================================================== + We are constantly looking for ways to make yo better! + May we anonymously report usage statistics to improve the tool over time? + More info: https://github.com/yeoman/insight & http://yeoman.io + ========================================================================== No + + _-----_ ╭──────────────────────────╮ + | | │ Welcome to the │ + |--(o)--| │ Blockstack app │ + --------- │ generator! │ + ( _U_ ) ╰──────────────────────────╯ + /___A___\ / + | ~ | + __'.___.'__ + |° Y + + ? Are you ready to build a Blockstack app in React? (Y/n) + ``` + +4. Respond to the prompts to populate the initial app. + + After the process completes successfully, you see a prompt similar to the following: + + ```bash + [fsevents] Success: + "/Users/theuser/repos/hello-blockstack/node_modules/fsevents/lib/binding/Release/node-v59-darwin-x64/fse.node" + is installed via remote npm notice created a lockfile as package-lock.json. + You should commit this file. added 1060 packages in 26.901s + ``` + +5. Run the initial application. + + ```bash + $ npm start + + > hello-blockstack@0.0.0 start /Users/moxiegirl/repos/hello-blockstack + > webpack-dev-server + + Project is running at http://localhost:8080/ + webpack output is served from / + 404s will fallback to /index.html + Hash: 4d2312ba236a4b95dc3a + Version: webpack 2.7.0 + Time: 2969ms + Asset Size Chunks Chunk Names + .... + Child html-webpack-plugin for "index.html": + chunk {0} index.html 541 kB [entry] [rendered] + [0] ./~/lodash/lodash.js 540 kB {0} [built] + [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. + + ![](images/blockstack-signin.png) + + At this point, the browser is running a Blockstack server on your local host. + This is for testing your applications only. + +6. Choose **Sign in with Blockstack** + + The system displays a prompt allowing you to create a new Blockstack ID or restore an existing one. + + ![](images/create-restore.png) + +7. Follow the prompts appropriate to your situation. + + If you are restoring an existing ID, you may see a prompt about your user + 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 + own `blockstack.id` display name, once you are signed in: + + ![](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 + + + + Hello, Blockstack! + + + + + ``` + + 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 + +In this section, you'll create an Android application in Android Studio. You'll +run the application in the emulator to test it. + +### Create a simple project + +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: + + +1. Open Android Studio and choose **Start a new Andriod Studio project**. + + If studio is already started, choose **File > New > New Project**. + +2. Enter these fields in the **Create Android Project** page. + + + + + + + + + + + + + + + + + + +
Application Namehello-android
Company domainUSERNAME.example.com
Project location/Users/USERNAME/AndroidStudioProjects/helloandroid
Include Kotlin supportSet (checked)
+ +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) + +9. Press **Finish**. + + 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 + +In this section, you run the appliation and create an emulator when prompted. + +1. Once the project is imported into studio, click the `app` module in the **Project** window. + +2. Then, select **Run > Run** (or click the green arrow in the toolbar). + + Studio prompts you to **Select Deployment Target**. + +3. Choose **Create New Virtual Device** and press **OK**. + + Studio prompts you to **Select Hardware**. + +4. Choose a Phone running Pixel XL. + + ![](images/select-hdw.png) + + Studio prompts you for a system image. + +5. Choose **Oreo** which is API level 27 and press **Next**. + + ![](images/oreo-api.png) + + Studio asks you to verify your new emulator configuration. + +6. Press **Finish**. + + The emulation takes a moment to build. Then, studio launches the emulation and opens your application. + + ![](images/hello-andriod-1.png) + + +### 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. + +1. In studio, open the `AndroidManifest.xml` file. + +2. Add an `` with the custom handler for Blockstack. + + ```XML + + + + + + + ``` + +2. Open the Project's `build.gradle` file. +3. Add the Jitpack repository `maven { url 'https://jitpack.io' }` to the `repositories` section. + + When you finish, that section looks like this: + + ```JS + allprojects { + repositories { + google() + jcenter() + maven { url 'https://jitpack.io' } + } + } + ``` + +4. Open the Module `build.gradle` file. +5. Set the `defaultConfig minSdkVersion` to `19`. + + When you are done, you should see (within your own username not `moxiegirl`): + + ```JS + android { + compileSdkVersion 27 + defaultConfig { + applicationId "com.example.moxiegirl.hello_android" + minSdkVersion 19 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + ... + } + ``` + +7. Below this, add the Blockstack Android SDK dependency to your project's `dependencies` list: + + When you are done you should see: + + ```JS + dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'com.android.support:design:27.1.1' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + implementation 'com.github.blockstack:blockstack-android:0.4.0' + } + + ``` + + **NOTE**: Ignore the warning on the appcompat` dependencies. + +8. Sync your project. + + ![](images/sync-project.png) + + Be sure to check the sync completed successfully. + + ![](images/sync-success.png) + +10. Run your app in the emulator. + + You've made a lot of changes, make sure the emulator is still running + correctly. + +### Add a simple interface + +1. Open the `app/res/layout/activity_main.xml` file. + + 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: + + The new interface includes a `BlockstackSignInButton` which is provided by + the SDK. This SDK includes a themed "Sign in with Blockstack" button + (`BlockstackSignInButton`). You use this button here with the + `org.blockstack.android.sdk.ui.BlockstackSignInButton` class. + + ```XML + + + + + + + + + ``` + + This codes adds a button and some text to your application. + +4. Choose **Run > Apply changes**. + +5. Choose **Run > Run app** in the emulator. + + The emulator now contains a new interface with a button: + + ![](images/new-interface.png) + +### Add session & authentication code + +1. Open the `MainActivity.kt` file. +2. Add some additional imports to the top below the `android.os.Bundle` import. + + When you are done, your imports should appear as follows: + + ```kotlin + import android.content.Intent + import android.os.Bundle + import android.support.v7.app.AppCompatActivity + import android.view.View + import kotlinx.android.synthetic.main.activity_main.* + import org.blockstack.android.sdk.BlockstackSession + import org.blockstack.android.sdk.Scope + import org.blockstack.android.sdk.UserData + import org.blockstack.android.sdk.toBlockstackConfig + ``` +3. Add a variable for the Blockstack session before `onCreate`. + + ```kotlin + class MainActivity : AppCompatActivity() { + + private var _blockstackSession: BlockstackSession? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + } + } + ``` + +4. Replace the existing the `onCreate` function with the following: + + ```kotlin + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + val scopes = arrayOf(Scope.StoreWrite) + val config = "https://flamboyant-darwin-d11c17.netlify.com" + .toBlockstackConfig(scopes) + + _blockstackSession = BlockstackSession(this, config) + + signInButton.isEnabled = true + + signInButton.setOnClickListener { view: View -> + blockstackSession().redirectUserToSignIn { + // only called on error + } + } + if (intent?.action == Intent.ACTION_VIEW) { + // handle the redirect from sign in + handleAuthResponse(intent) + } + } + ``` + + This new `onCreate` does several things: + + * Define the initial state for the `signInButton`. + * 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. + + 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 + use an existing app that is identical to the `hello-world` you created + earlier. For a production version, you'll need to replace `appDomain`, + `redirectURI`, `manifestURI` and `scopes` with values appropriate for your + app. + +5. Add a private function to reflect when a user successfully signs in. + + ```kotlin + private fun onSignIn(userData: UserData) { + userDataTextView.text = "Signed in as ${userData.decentralizedID}" + signInButton.isEnabled = false + } + ``` + +6. Handle sign in requests with an `onNewIntent` function if the activity was already opened when signing in + + 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 + 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) { + // The user is now signed in! + runOnUiThread { + onSignIn(userData.value!!) + } + } + }) + } + } + } + ``` + +8. Add the convenience method to access the blockstack session. + + ```kotlin + fun blockstackSession() : BlockstackSession { + val session = _blockstackSession + if(session != null) { + return session + } else { + throw IllegalStateException("No session.") + } + } + ``` + +9. Verify your final `MainActivity.kt` code looks like this: + + ```kotlin + class MainActivity : AppCompatActivity() { + + private var _blockstackSession: BlockstackSession? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + signInButton.isEnabled = false + + val scopes = arrayOf(Scope.StoreWrite) + val config = "https://flamboyant-darwin-d11c17.netlify.com" + .toBlockstackConfig(scopes) + + _blockstackSession = BlockstackSession(this, config) + signInButton.isEnabled = true + + signInButton.setOnClickListener { view: View -> + blockstackSession().redirectUserToSignIn { + // only called on error + } + } + if (intent?.action == Intent.ACTION_VIEW) { + handleAuthResponse(intent) + } + } + + private fun onSignIn(userData: UserData) { + userDataTextView.text = "Signed in as ${userData.decentralizedID}" + + signInButton.isEnabled = false + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + + if (intent?.action == Intent.ACTION_VIEW) { + 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) { + // The user is now signed in! + runOnUiThread { + onSignIn(userData.value!!) + } + } + }) + } + } + } + + fun blockstackSession() : BlockstackSession { + val session = _blockstackSession + if(session != null) { + return session + } else { + throw IllegalStateException("No session.") + } + } + } + ``` + +### Run the final app in the emulator + +1. Choose **Run > Apply changes**. +2. Choose **Run > Run app** in the emulator. +3. When you see the application open, choose **Sign in with Blockstack**. + + The system prompts you how to open. + + ![](images/chrome-prompt.png) + +4. Choose **Chrome** and click **ALWAYS**. +5. Move through the rest of the Chrome prompts. + + The system presents you with your final application. + + ![](images/final-app.png) + +6. Work through the Blockstack prompts to login. + + +## Where to go next + +Congratulations, you've completed your Android app using the new, pre-release +Blockstack Android SDK. Thank you for trying this pre-release. Please let us +know about your experience by tweeting to +[@blockstack](https://twitter.com/blockstack). + +Learn more about Blockstack by [trying another tutorial](https://blockstack.org/tutorials). diff --git a/_browser/.svn/entries b/_browser/.svn/entries new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/_browser/.svn/entries @@ -0,0 +1 @@ +12 diff --git a/_browser/.svn/format b/_browser/.svn/format new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/_browser/.svn/format @@ -0,0 +1 @@ +12 diff --git a/_browser/.svn/pristine/04/04f3a32b0bc311047a20e12c72428e50812cdbd9.svn-base b/_browser/.svn/pristine/04/04f3a32b0bc311047a20e12c72428e50812cdbd9.svn-base new file mode 100644 index 00000000..829f7c1f Binary files /dev/null and b/_browser/.svn/pristine/04/04f3a32b0bc311047a20e12c72428e50812cdbd9.svn-base differ diff --git a/_browser/.svn/pristine/07/0760488b80dc376bd96b4dd0ec94f4e79292cf9b.svn-base b/_browser/.svn/pristine/07/0760488b80dc376bd96b4dd0ec94f4e79292cf9b.svn-base new file mode 100644 index 00000000..36684bff --- /dev/null +++ b/_browser/.svn/pristine/07/0760488b80dc376bd96b4dd0ec94f4e79292cf9b.svn-base @@ -0,0 +1,330 @@ +--- +layout: learn +permalink: /:collection/:path.html +--- +# Hello, Blockstack Tutorial + +In this tutorial, you generate a simple application on Blockstack. The application +is a single-page application (SPA) that runs completely client-side. The +application has no backend API to talk to, other than the identity and storage +API that the user provides. In this sense, the application is a completely +decentralized, server-less application. You work through the following sections: + +* TOC +{:toc} + +## About this tutorial and the prerequisites you need + +For this tutorial, we will use the following tools: + +- `npm` to manage dependencies and scripts +- `browserify` to compile node code into browser-ready code +- `blockstack.js` to authenticate the user and work with the user's identity/profile information + +At minimum, Blockstack requires macOS High Sierra. This tutorial was written for +a user running macOS High Sierra 10.13.4. The application you build is a +React.js application that is completely decentralized and server-less. While +not strictly required to follow along, basic familiarity with React.js is +helpful. + +When complete, the app is capable of the following: + +- authenticating users using Blockstack +- posting new statuses +- displaying statuses in the user profile +- looking up the profiles and statuses of other users + +The basic identity and storage services are provided by `blockstack.js`. To test +the application, you need to have already registered a Blockstack ID. + +The tutorial relies on the `npm` dependency manager. Before you begin, verify +you have installed `npm` using the `which` command to verify. + +```bash +$ which npm +/usr/local/bin/npm +``` + +If you don't find `npm` in your system, [install +it](https://www.npmjs.com/get-npm). + +Finally, make sure you have [created at least one Blockstack ID]({{ site.baseurl }}/browser/ids-introduction.html#create-an-initial-blockstack-id). You'll use this ID to interat with the application. + +## Use npm to install Yeoman and the Blockstack App Generator + +You use `npm` to install Yeoman. Yeoman is a generic scaffolding system that +helps users rapidly start new projects and streamline the maintenance of +existing projects. + + +1. Install Yeoman. + + ```bash + npm install -g yo + ``` +2. Install the Blockstack application generator. + + ```bash + npm install -g generator-blockstack + ``` + +## Generate an initial Blockstack application + +In this section, you build an initial React.js application called `hello-world-tutorial`. + +1. Create the `hello-world-tutorial` directory. + + ```bash + mkdir hello-world-tutorial + ``` + +2. Change into your new directory. + + ```bash + cd hello-world-tutorial + ``` + +3. Use Yeoman and the Blockstack application generator to create your initial `hello-world-tutorial` application. + + ```bash + yo blockstack + ``` + + You should see several interactive prompts. + + ```bash + $ yo blockstack + + _-----_ ╭──────────────────────────╮ + | | │ Welcome to the │ + |--(o)--| │ Blockstack app │ + `---------´ │ generator! │ + ( _´U`_ ) ╰──────────────────────────╯ + /___A___\ / + | ~ | + __'.___.'__ + ´ ` |° ´ Y ` + + ? Are you ready to build a Blockstack app in React? (Y/n) + ``` + +4. Respond to the prompts to populate the initial app. + + After the process completes successfully, you see a prompt similar to the following: + + ```bash + ... + create public/icon-192x192.png + create public/index.html + create public/robots.txt + create public/manifest.json + + + I'm all done. Running npm install for you to install the required dependencies. If this fails, try running the command yourself. + ``` + +Depending on your environment you may have some problems with the `npm` packages. Go ahead and fix these before continuing to the next section. + +## Review the basic application structure + +The initial application you create is a generic Javascript application you run +with a local express node. Before you continue, take a moment to examine the +structure of this generic application structure: + +| File | Description | +|------------------|-----------------------------------| +| .editorconfig | Sets universal values for editor. | +| .gitignore | Git configuration file. | +| firebase.json | Configuragion for mobile application.| +| package.json | Specifies required packages. | +| requires.js | A Javascript module loader. | +| server.js | Simple static server configuration.| + +In the `public` folder you find these files: + +| File | Description | +|------------------|-----------------------------------| +| app.css | Contains application styles. | +| app.js | Main application file. | +| boostrap.min.css | Minifield css for production. | +| icon-192x192.png | Application icon | +| index.html | Single page. | +| manifest.json | Tells the browser about the application and how it should behave.| +| robots.txt | Configures crawling and indexing. | + +The simple static file server in the `server.js`file serves all of the files in +the `/public` directory, including `index.html`, `app.js`, `bootstrap.min.css` +and `app.css`. The main file of the application is in the `app.js`. It contains +the majority of the application logic. + +## Start the server and view the application + +When you start the server, it will create a Node.js server, start it locally, +and open your browser 'http://localhost:5000'. From the root of your new application directory: + +1. Start the application server. + + ```bash + npm start + ``` + + The first time you run it, your system prompts you to accept incoming connections. + + ![Network Connection](images/network-connections.gif) + +2. Choose **Allow**. + +3. Open your browser to `http://localhost:8080`. + + You should see a simple application: + + ![](images/initial-app.gif) + +4. Choose **Sign In with Blockstack**. + + The application detects whether the user has the Blockstack client edition installed or + not. This is done automatically by the Blockstack API, more about this later. + What the browser displays depends on the users' current state. + + | Using web app | Has client edition installed | + |------------------|-----------------------------------| + | ![](images/login-choice.png) | ![](images/login.gif) | + + If the user logged into the Blockstack Browser but not reset it, the user can + simply use the exiting identity. + + ![](images/login-no-auth.png) + + If the user chooses **Deny**, the Blockstack Browser displays its + **Home** page but the user is not logged into the sample application. + +5. Leave your new application running and move onto the next section. + +## Understand the generated application code + +In this section, you look at the basic application generated with the `yo +blockstack` command. The generated code contains simple authentication methods +that allow a user to log into the browser. The main application code is located +in the `public/app.css` file. Open this file now. + +All of the code in the file is wrapped in an event +listener. + +```js +document.addEventListener("DOMContentLoaded", function(event) { +}) +``` + +This listener that waits until the DOM content is loaded. Then, it creates an auth request and redirects the user to sign in: + +```js +document.getElementById('signin-button').addEventListener('click', function() { + blockstack.redirectUserToSignIn() +}) +``` + +You can find the `redirectUserToSignIn()` function is part of the [Blockstack Javascript documentation](https://blockstack.github.io/blockstack.js/). There is also a sign out button handler. This handler deletes the local user data and signs the user out: + +```js +document.getElementById('signout-button').addEventListener('click', function() { + blockstack.signUserOut(window.location.origin) +}) +``` + +The handlers are followed by a `showProfile()` function for showing the user's profile: + +```js +function showProfile(profile) { + var person = new blockstack.Person(profile) + document.getElementById('heading-name').innerHTML = person.name() ? person.name() : "Nameless Person" + if(person.avatarUrl()) { + document.getElementById('avatar-image').setAttribute('src', person.avatarUrl()) + } + document.getElementById('section-1').style.display = 'none' + document.getElementById('section-2').style.display = 'block' +} +``` + +Each `getElementById()` function refers to elemments in the `index.html` file. + +Once a user is successfully signed in, there is logic for loading the user +profile and displaying the application. As illustrated earlier, there are +several states the user can be in: + +- The user is already signed in +- The user has a pending sign in request +- The user is signed out + +The application handles these situtations as followed: + +```js +if (blockstack.isUserSignedIn()) { + var profile = blockstack.loadUserData().profile + showProfile(profile) +} else if (blockstack.isSignInPending()) { + blockstack.handlePendingSignIn().then(function(userData) { + window.location = window.location.origin + }) +} +``` + +When the user is signed in, Blockstack loads the user data from local storage +and displays the profile with the `showProfile()` function. When the user has a +pending sign in request, the appplication signs the user in and redirects the +user back to the home page. + +### Application manifest + +The application's `/public/manifest.json` file configures your app. The +configurations dictate how the application is displayed in auth views and on +user home screens. The contents are very simple: + +```json +{ + "name": "Hello, Blockstack", + "start_url": "localhost:5000", + "description": "A simple demo of Blockstack Auth", + "icons": [{ + "src": "https://helloblockstack.com/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }] +} +``` + +Keep it as is or fill it in with new information that describes your app. + +### Save your application code + +Complete the tutorial by storing your app code on GitHub. Before you begin, make sure you have a GitHub account and have configured your environment to use it. + +1. Initialize the application code as a Git repo. + + ```bash + git init + ``` + +2. Add and commit all of the files: + + ```bash + git add . && git commit -m "first commit" + ``` + +3. In GitHub, create a `hello-blockstack` repository. + +4. Back in your termininal window, add a remote for GitHub. + + Make sure to fill in your username: + + ```bash + git remote add origin git@github.com:YOUR_USERNAME_HERE/hello-blockstack.git + ``` + +5. Push your new code to the master branch of the remote repo: + + ``` + git push origin master + ``` + +You're done! You just built your first Blockstack app and shipped the code. +You're well on your way to becoming a Blockstack app legend. diff --git a/_browser/.svn/pristine/08/085c1a3260d4d04fcd82252787ba093d06446210.svn-base b/_browser/.svn/pristine/08/085c1a3260d4d04fcd82252787ba093d06446210.svn-base new file mode 100644 index 00000000..bf6c096a Binary files /dev/null and b/_browser/.svn/pristine/08/085c1a3260d4d04fcd82252787ba093d06446210.svn-base differ diff --git a/_browser/.svn/pristine/12/1284f902d27c0fdb01787c315fa61ee525538d65.svn-base b/_browser/.svn/pristine/12/1284f902d27c0fdb01787c315fa61ee525538d65.svn-base new file mode 100644 index 00000000..5352b913 Binary files /dev/null and b/_browser/.svn/pristine/12/1284f902d27c0fdb01787c315fa61ee525538d65.svn-base differ diff --git a/_browser/.svn/pristine/28/28885ce546124804666f1c735f1fb916582a1a98.svn-base b/_browser/.svn/pristine/28/28885ce546124804666f1c735f1fb916582a1a98.svn-base new file mode 100644 index 00000000..9fef9de2 Binary files /dev/null and b/_browser/.svn/pristine/28/28885ce546124804666f1c735f1fb916582a1a98.svn-base differ diff --git a/_browser/.svn/pristine/2c/2cb66479d94646ba1c3c651f26dbd9683e929114.svn-base b/_browser/.svn/pristine/2c/2cb66479d94646ba1c3c651f26dbd9683e929114.svn-base new file mode 100644 index 00000000..006eeca5 Binary files /dev/null and b/_browser/.svn/pristine/2c/2cb66479d94646ba1c3c651f26dbd9683e929114.svn-base differ diff --git a/_browser/.svn/pristine/2e/2e837afccc4a402a90dc0b7e580109e49e3252e2.svn-base b/_browser/.svn/pristine/2e/2e837afccc4a402a90dc0b7e580109e49e3252e2.svn-base new file mode 100644 index 00000000..a5f0c27f Binary files /dev/null and b/_browser/.svn/pristine/2e/2e837afccc4a402a90dc0b7e580109e49e3252e2.svn-base differ diff --git a/_browser/.svn/pristine/2f/2f00af279deecacd5b47bdc32a0106e23b2a2f64.svn-base b/_browser/.svn/pristine/2f/2f00af279deecacd5b47bdc32a0106e23b2a2f64.svn-base new file mode 100644 index 00000000..019c67db Binary files /dev/null and b/_browser/.svn/pristine/2f/2f00af279deecacd5b47bdc32a0106e23b2a2f64.svn-base differ diff --git a/_browser/.svn/pristine/30/30473db14d0ed5ac772c32ab2e89375faa2b0133.svn-base b/_browser/.svn/pristine/30/30473db14d0ed5ac772c32ab2e89375faa2b0133.svn-base new file mode 100644 index 00000000..c2626b50 Binary files /dev/null and b/_browser/.svn/pristine/30/30473db14d0ed5ac772c32ab2e89375faa2b0133.svn-base differ diff --git a/_browser/.svn/pristine/30/30e89a5d274e5137e687939f31ca471aea7462a3.svn-base b/_browser/.svn/pristine/30/30e89a5d274e5137e687939f31ca471aea7462a3.svn-base new file mode 100644 index 00000000..787392e1 --- /dev/null +++ b/_browser/.svn/pristine/30/30e89a5d274e5137e687939f31ca471aea7462a3.svn-base @@ -0,0 +1,27 @@ +# Tutorials + +**Note: This data is being digested by blockstack.org. Do not change the formatting of this list unless you first make an adjustment to the code on blockstack.org.** + +### Multi-player Storage + +- urlSlug: multi-player-storage +- image: /images/tutorials/multi-player-storage.png +- description: Build a decentralized micro-blogging app using multi-player Gaia storage. + +### Managing Data with Gaia + +- urlSlug: managing-data-with-gaia +- image: /images/tutorials/managing-data-with-gaia.png +- description: This series will focus on teaching you to think like a Blockstack developer working with Gaia. + +### Blockstack Todo + +- urlSlug: todo-list +- image: /images/tutorials/todo-list.png +- description: Walk through creating a basic Todo application with Blockstack. Learn about Sign In flow and Gaia storage. + +### Hello Blockstack + +- urlSlug: hello-blockstack +- image: /images/tutorials/hello-blockstack.jpg +- description: Build a simple single-page JavaScript application that runs completely client-side without any servers. diff --git a/_browser/.svn/pristine/33/33f4fbc3c99fe5df9c5eb23cc4aaf25165722419.svn-base b/_browser/.svn/pristine/33/33f4fbc3c99fe5df9c5eb23cc4aaf25165722419.svn-base new file mode 100644 index 00000000..433ef3d5 Binary files /dev/null and b/_browser/.svn/pristine/33/33f4fbc3c99fe5df9c5eb23cc4aaf25165722419.svn-base differ diff --git a/_browser/.svn/pristine/37/373b7d67a3d5c2de4723fcd45470854cf0c5ca6e.svn-base b/_browser/.svn/pristine/37/373b7d67a3d5c2de4723fcd45470854cf0c5ca6e.svn-base new file mode 100644 index 00000000..26d88672 Binary files /dev/null and b/_browser/.svn/pristine/37/373b7d67a3d5c2de4723fcd45470854cf0c5ca6e.svn-base differ diff --git a/_browser/.svn/pristine/3f/3f89163556affc6e77a6630136bf6897bc9ae8f6.svn-base b/_browser/.svn/pristine/3f/3f89163556affc6e77a6630136bf6897bc9ae8f6.svn-base new file mode 100644 index 00000000..1d95fee1 Binary files /dev/null and b/_browser/.svn/pristine/3f/3f89163556affc6e77a6630136bf6897bc9ae8f6.svn-base differ diff --git a/_browser/.svn/pristine/42/423c91a747d0f3570fb0d63199c9adcbe6baef1d.svn-base b/_browser/.svn/pristine/42/423c91a747d0f3570fb0d63199c9adcbe6baef1d.svn-base new file mode 100644 index 00000000..d2c2dda2 Binary files /dev/null and b/_browser/.svn/pristine/42/423c91a747d0f3570fb0d63199c9adcbe6baef1d.svn-base differ diff --git a/_browser/.svn/pristine/49/49a137f4f026b72e9ba4af3fd546fe8baff34c09.svn-base b/_browser/.svn/pristine/49/49a137f4f026b72e9ba4af3fd546fe8baff34c09.svn-base new file mode 100644 index 00000000..75c17f14 --- /dev/null +++ b/_browser/.svn/pristine/49/49a137f4f026b72e9ba4af3fd546fe8baff34c09.svn-base @@ -0,0 +1,328 @@ +--- +title: Tour of a Blockstack application +description: Walk through creating a basic Todo application with Blockstack. Learn about Sign In flow and Gaia storage. +image: /images/article-photos/chalkboard.jpg +youtube: https://www.youtube.com/embed/oyvg-h0obFw +--- + +In this tutorial, you build the code for and run a single-page application (SPA) +with Blockstack and Vue.js. Once the application is running, you take a tour +through the applications' Blockstack functionality. You'll learn how it manages +authentiation using a Blockstack ID and how it stores information associated +with that ID using Blockstack Storage (Gaia). + +## Prerequisites + +Make sure you have [created at least one Blockstack ID](ids-introduction#create-an-initial-blockstack-id). You'll use this ID to Finteract with the Todo application. + +The applicaton code relies on both the `npm` and the `yarn` package managers. +Before you begin, verify you have these tools `npm` using the `which` command to +verify. + +```bash +$ which npm +/usr/local/bin/npm +$ which yarn +/usr/local/bin/yarn +``` + +[Install npm](https://www.npmjs.com/get-npm), [install +yarn](https://yarnpkg.com/lang/en/docs/install/#mac-stable), or both as needed. You + +While it stands alone, this tour does on the information from the [Hello +Blockstack tutorial](hello-blockstack). If you haven't worked through that +tutorial, you may want to do that before continuing. + + +## Install the applicaton code and retrieve the dependencies + +You can clone the source code with `git` or [download and unzip the code from +the +repository](https://github.com/blockstack/blockstack-todos/archive/master.zip). +These instructions assume you are cloning. + + +1. Install the code by cloning it. + + ``` + $ git clone git@github.com:blockstack/blockstack-todos.git + ``` + +2. Change to directory to the root of the code. + + ``` + $ cd blockstack-todos + ``` + +2. Use yarn to install the dependencies. + + + ``` + $ yarn install + yarn install v1.9.2 + info No lockfile found. + ... + [4/5] 🔗 Linking dependencies... + [5/5] 📃 Building fresh packages... + success Saved lockfile. + ✨ Done in 19.90s. + ``` + +## Understand the important application files + +The Todo application has a basic Vue.js structure. There are several configuration files but the central programming files are in the `src` directory: + +| File | Description | +|-----------------|-------------| +| `main.js` | Application initialization. | +| `App.vue ` | Code for handling the `authResponse`. | +| `Landing.vue ` | Code for the initial sign on page. | +| `Dashboard.vue` | Application data storage and user sign out. | + +The example application runs in a node server on your local host. In the next section, you start the application and interact with it. + +1. Start the application. + + ``` + $ npm run start + ``` + + You should see a simple application: + + ![](images/todo-sign-in.png) + + 2. Choose **Sign In with Blockstack**. + + +## Understand the sign in process + +At startup, the Todo application detects whether the user has the Blockstack client edition +installed or not. This is done automatically by the Blockstack API, more +about this later. What the authenticator displays depends on which whether the user has installed the Blockstack Authenticator client edition or not. + +| Client edition installed | Not installed | +|------------------|-----------------------------------| +| ![](images/login.gif) | ![](images/login-choice.png)| + +If the user was logged into the Blockstack authenticator (web or client) but +did not reset it, the web application to use the current identity: + +![](images/login-no-auth.png) + +If the user chooses **Deny**, the Blockstack authenticator opens but the user +is not logged into the sample application. + +![](images/windows-browser.png) + +If the login to the application is successful, the user is presented with the application: + +![](images/todo-app.png) + +Clicking the **Sign In With Blockstack** button brings up a modal that prompts +you to use an existing ID's session, create a new ID, or reset the browser with +another ID. When Blockstack is provided an ID, it generates an _ephemeral key_ +within the application. An ephemeral key is generated for each execution of a +key establishment process. This key is just used for the particular instance of +the application, in this case to sign a **Sign In** request. + +Blockstack also generates a public key token which is sent to the authenticator +as an `authRequest` from the authenticator to your local blockstack-core node. +The signed authentication request is sent to Blockstack through a JSON Web +Token. The JWT is passed in via a URL query string in the `authRequest` +parameter: +`https://browser.blockstack.org/auth?authRequest=j902120cn829n1jnvoa...`. To +decode the token and see what information it holds: + +1. Copy the `authRequest` string from the URL. +2. Navigate to [jwt.io](http://jwt.io/). +3. Paste the full token there. + + The output should look similar to below: + + ```json + { + "jti": "3i96e3ad-0626-4e32-a316-b243154212e2", + "iat": 1533136622, + "exp": 1533140228, + "iss": "did:btc-addr:1Nh8oQTunbEQWjrL666HBx2qMc81puLmMt", + "public_keys": [ + "0362173da080c6e1dec0653fa9a3eff5f5660546e387ce6c24u04a90c2fe1fdu73" + ], + "domain_name": "http://localhost:8080", + "manifest_uri": "http://localhost:8080/manifest.json", + "redirect_uri": "http://localhost:8080/", + "version": "1.2.0", + "do_not_include_profile": true, + "supports_hub_url": true, + "scopes": [ + "store_write" + ] + } + ``` + +>**Note**: +> 1. The `iss` property is a decentralized identifier or `did`. This identifies you and your name to the application. The specific `did` is a `btc-addr`. +> 2. The Blockstack JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in [Javascript](https://github.com/blockstack/jsontokens-js) and [Ruby](https://github.com/blockstack/ruby-jwt-blockstack) available on the Blockstack Github to allow you to work with these tokens. + +When the blockstack-core receives the `authRequest`, it generates a session token and +returns an authentication response to the application. This response is similar +to the `authRequest` above in that the `authResponse` includes a private key +intended only for the application. This allows the application to encrypt data +on your personal Blockstack storage. + +You are now logged into the Todo application! + +## Undder the covers in the sign in code + +Now, go to the underlying `blockstack-todo` code you cloned or downloaded. Sign +in and sign out is handled in each of these files: + +| File | Description | +|-----------------|-------------| +| `App.vue ` | Handles the `authResponse`. | +| `Landing.vue ` | Generates the `authRequest`. | +| `Dashboard.vue` | Handles sign out. | + +The `src/components/Landing.vue` code calls a [`redirectToSignIn()`](https://blockstack.github.io/blockstack.js#redirectToSignIn) function which generates the `authRequest` and redirects the user to the Blockstack authenticator: + +```js +signIn () { + const blockstack = this.blockstack + blockstack.redirectToSignIn() +} +``` + +Once the user authenticates, the application handles the `authResponse` in the `src/App.vue` file. : + +```js +if (blockstack.isUserSignedIn()) { + this.user = blockstack.loadUserData().profile +} else if (blockstack.isSignInPending()) { + blockstack.handlePendingSignIn() + .then((userData) => { + window.location = window.location.origin + }) +} +``` + +If [`blockstack.isUserSignedIn()`](https://blockstack.github.io/blockstack.js/#isusersignedin) is true, the user was previously signed in so Blockstack pulls the data from the browser and uses it in our application. If the check on [`blockstack.isSignInPending()`](https://blockstack.github.io/blockstack.js/#issigninpending) is true, a previous `authResponse` was sent to the application but hasn't been processed yet. The `handlePendingSignIn()` function processes any pending sign in. + +Signout is handled in `src/components/Dashboard.vue`. +```js +signOut () { + this.blockstack.signUserOut(window.location.href) +} +``` + +The method allows the application creator to decide where to redirect the user upon Sign Out: + + +## Working with the application + +Now trying adding a few todos using the application. For example, try making a list of applications you want to see built on top of Blockstack: + +![](images/make-a-list.png) + +Each list is immediately stored in the Gaia Hub linked to your Blockstack ID. +For more information about the Gaia hub, see the [hub +repository](https://github.com/blockstack/gaia). You can fetch the `todos.json` +file you just added by opening the Javascript console and running the following +command: + +```Javascript +blockstack.getFile("todos.json", { decrypt: true }).then((file) => {console.log(file)}) +``` + +You should see a JSON with the todos you just added: + +```json +[ + { + "id":2, + "text":"Software package manager secured by the blockchain", + "completed":false + }, + { + "id":1, + "text":"Mutable torrents with human readable names", + "completed":false + }, + { + "id":0, + "text":"Decentralized twitter", + "completed":false + } +] +``` + + +Now, add another todo and check it off. When you fetch the newly generated file +using the Javascript console it will reflect the change look for `"completed":true`: + +```json +[ + { + "id":3, + "text":"Blockstack Todo", + "completed":true + }, + { + "id":2, + "text":"Software package manager secured by the blockchain", + "completed":false + }, + ... +] +``` + +Now that you have seen the application in action, dig into how it works. + + +## Implementing storage + +Now, go to the underlying `blockstack-todo` code you cloned or downloaded. The +application interactions with your Gaia Hub originate in the +`src/components/Dashboard.vue` file. First lets see where the changes to the +Todos are processed: + +```js +todos: { + handler: function (todos) { + const blockstack = this.blockstack + + // encryption is now enabled by default + return blockstack.putFile(STORAGE_FILE, JSON.stringify(todos)) + }, + deep: true +} +``` + +Tje `todos` JSON object is passed in and the [`blockstack.putFile()`](https://blockstack.github.io/blockstack.js/#putfile) method to store it in our Gaia Hub. + +The code needs to read the Todo items from the storage with the [`blockstack.getFile()`](https://blockstack.github.io/blockstack.js/#getfile) method which returns a promise: + +```js +fetchData () { + const blockstack = this.blockstack + blockstack.getFile(STORAGE_FILE) // decryption is enabled by default + .then((todosText) => { + var todos = JSON.parse(todosText || '[]') + todos.forEach(function (todo, index) { + todo.id = index + }) + this.uidCount = todos.length + this.todos = todos + }) +}, +``` + +The `todos` data is retrieved from the promise. + + +## Summary + +You now have everything you need to construct complex applications complete with authentication and storage on the Decentralized Internet. Why not try coding [a sample application that accesses multiple profiles](multi-player-storage.md). + +If you would like to explore the Blockstack APIs, you can visit the [Blockstack Core API](https://core.blockstack.org/) documentation or the [Blockstack JS API](https://blockstack.github.io/blockstack.js). + + Go forth and build! diff --git a/_browser/.svn/pristine/55/5500a797259a620714f1c576c579f117982590db.svn-base b/_browser/.svn/pristine/55/5500a797259a620714f1c576c579f117982590db.svn-base new file mode 100644 index 00000000..aa136ba1 Binary files /dev/null and b/_browser/.svn/pristine/55/5500a797259a620714f1c576c579f117982590db.svn-base differ diff --git a/_browser/.svn/pristine/63/630ab4b5cbd3ff99dde5761ac5f475eb39dc3c9b.svn-base b/_browser/.svn/pristine/63/630ab4b5cbd3ff99dde5761ac5f475eb39dc3c9b.svn-base new file mode 100644 index 00000000..738bb384 --- /dev/null +++ b/_browser/.svn/pristine/63/630ab4b5cbd3ff99dde5761ac5f475eb39dc3c9b.svn-base @@ -0,0 +1,288 @@ +--- +layout: usenew +permalink: /:collection/:path.html +--- +# Use the Blockstack Browser +{:.no_toc} + +The Blockstack Browser gives users the ability to explore and use the +decentralized applications (dapps). The decentralized applications are a new way +to interact with the internet. Dapps give users control of their data. Data +about them personally, name, birthdate, phone number and data about what they do +such as visiting a website or buying an item. + +* TOC +{:toc} + +## Understand the Blockstack Browser + +Through the Blockstack browser application you can create an identity. An identity +represents you as you interact with others through Dapps. The Blockstack +Browser is itself, a simple Dapp. It allows you to: + +* create one or more identities +* send and receive bitcoin +* manage the storage of your profile and application data +* find and launch Dapps + +There are editorions of the Blockstack Browser, the web edition is an +application you access through your web browser by simply [visit the +applications' address](https://browser.blockstack.org/) in your computer's +browser. You can also install the browser as a client application on your +computer. + +If all you want to do is create, manage, and fund an identity and then interact +with Dapps, you can simply use the web edition. If you have concerns about net +censorship, hightened security concerns, or develop a Dapp yourself, you may +want to download and install the browser's client edition. + +## Using the Browser on public computers + +Before you use the web application, it is important to note that once you log +into the application with the brower, your session does not expire until you +choose **Settings > RESET BROWSER**. For this reason, you should be careful +when using the browser on public computers. + +If you are in a library, for example, and log into the browser, simply +closing the tab or even rebooting the computer does not log you out. Instead, +you should be sure to choose **Settings > RESET BROWSER** before leaving the web +application. + +For more informatin about your identity and the browser, see [Get and use a Blockstack IDs](ids-introduction). + +## Install the client edition + +Remember, for most users the Blockstack Browser web application should +suffice. You only need to install the client if you have additional, advanced +concerns about Internet or identity. Though not required, some Dapp developrs +may find it useful to install the client edition. + +The Blockstack Browser installer is a _multiple-context_ installer. If you +run it as a user, the installation is avalable only for that user. If you +install as administrator, the installation installs for all users. To find an +installer for your operating system, visit [the Blockstack install +page](https://blockstack.org/install). + +### On Mac + +Installation requires that you have macOS High Sierra 10.12 or higher. Do the following to install: + +1. Download the OSX installer from [the browser installation page](https://blockstack.org/install). +2. Double-click the downloaded DMG file to launch the installer. + + ![](images/ubuntu-browser.png) + +3. Drag the Blockstack.app to the `Applications` folder. +4. Double-click the Blockstack.app to launch it. + + The system displays a notice about opening the file: + + ![](images/dmg-notice.png) + +5. Choose **Open**. + + The system opens your default browser with the Blockstack Browser + application, running from your machine (localhost). You'll also see the + Blockstack icon in your machine's + + ![](images/browser-on-mac.png) + + If you have loaded an identity already via the Blockstack web application, + you are already logged into the local application: + + ![](images/browser-on-mac-1.png) + + +### On Windows + +Installation requires that you have Windows 10 or higher. Do the following to +install: + +1. Download the Windows installer from from [the browser installation page](https://blockstack.org/install). +2. Double-click the installer package to launch it. + + ![](images/windows-installer.png) + +3. Open the Wiindows **Start** menu and click on the recently added **Blockstack Browser**. + + ![](images/windows-start.png) + + The system displays a Windows Security Alert. + + ![](images/windows-security.png) + +4. Choose to **Allow access**. + + The system opens in the Blockstack Browser application. + + ![](images/windows-browser.png) + + +### On Linux + +The Blockstack installation on Linux requires Docker. Before installing +Blockstack, [install the version of Docker appropriate for your operating system](https://docs.docker.com/install/). + +>**Note**: The Blockstack script used in this procedure runs `docker` commands. Depending on how you installed and configure Dockered on your system, it may or may not be necessary to have `root` or `sudo` privileges. For this reason, the commands below show the use of `sudo` when interacting with the script or the `docker` executable. If your installation allows running Docker with lower privileges, you can omit it. + + +1. Download the Linux installer from from [the browser installation page](https://blockstack.org/install). + + This downloads a `Blockstack-for-Linux-v0.30.0.sh` script to your local drive. + +2. Open a terminal and navigate to the directory containing the downloaded script. + + When the script downloads, it is not executable. + +3. Set the executable bit on the file. + + ```bash + $ chmod u+x Blockstack-for-Linux-v0.309.0.0.sh + ``` + +4. Enter the command without any arguments to see the available subcommands. + + ```bash + $ sudo ./Blockstack-for-Linux-v0.309.0.0.sh + blockstack docker launcher commands: + Install-protocol-handler -> install a protocol handler for blockstack:// links + ... + ``` + +5. Use the script to `pull` the Blockstack Docker images you need. + + + ```bash + $ sudo ./Blockstack-for-Linux-v0.309.0.0.sh pull + ``` + + Depending on your network speed, this can take some time. + +7. Use the `docker image ls` command to confirm you have the image. + + ```bash + $ sudo docker image Is + REPOSITORY TAG IMAGE ID CREATED + quay.io/blockstack/blockstack-browser v0.30.0 ad05fd844f59 2 days ago + ``` + +8. Install the protocol handler + + ```bash + $ sudo ./Blockstack-for-Linux-vO.30.0.sh install-protocol-handler
 + Registering protocol handler + ``` + +9. Start the Blockstack containers. + + ```bash + $ sudo ./Blockstack-for-Linux-vO.30.0.sh start + c3092592e59abe3559fdb49d070a7aa5e99165c7d9f2flla20ecaf4e0dfc2f46
 + cd92f61ae473d54398da987f5023f5462b29c03f08584ebb3c9fIbb4cd790c69
 + Registering protocol handler + ``` + + The system launches the Blockstack Browser application for you. + + ![](images/ubuntu-browser.png) + +Until you stop the Blockstack containers, the application will continue to run +on your system. To display the status of the Blockstack containers, you can use +the `docker container ls` command. + +{% raw %} +```bash +$ sudo docker container ls --format '{{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}' +``` +{% endraw %} + +Use `./Blockstack-for-Linux-vO.30.0.sh stop` to stop the Blockstack Browser and its containers. + + +## Uninstall the browser + +If you installed the browser using an installer, follow the instructions for +your operating system. + +### On Mac + +1. Quit the Blockstack application if it is running. + + ![](images/quit-blockstack.png) + +2. Check if you have a Blockstack device and eject it if you do. + + ![](images/eject-blockstack.png) + +3. Use the Finder to open the **Applications** folder. +4. Locate the Blockstack application. +5. Open your `Applications` folder and locate the **Blockstack.app**. +6. Drag the appliation to the trash. +7. Delete the `/Users/USERNAME/Library/Application Support/Blockstack` folder. + + From the command line: + + ```bash + $ rm -r /Users/moxiegirl/Library/Application\ Support/Blockstack + ``` + +### On Windows + +1. Open the **Start** menu. +2. Click **Settings > System**. +3. Open for the **Apps & features** item. + + ![](images/eject-blockstack.png) + +4. Locate the **Blockstack Browser** and choose **Uninstall**. + + ![](images/browser-uninstall.png) + + +### On Linux + +Your Blockstack instalaltion relies on Docker containers and their associated +images. It also includes a supporting protocol handler you must remove. If you +installed Docker so that you can run Blockstack, you can uninstall Docker as well, +but that is not explained here. + +Do the following to uninstall Blockstack: + +1. Stop and remove the Docker containers if they are running. + + ```bash + $ sudo ./Blockstack-for-Linux-vO.30.0.sh stop + stopping the running blockstack-browser containers + 69a686799d4f + 56fc6189ff97 + 69a686799d4f + 56fc6189ff97 + ``` + +2. Remove the associated Blockstack images. + + ```bash + $ sudo docker image ls + REPOSITORY TAG IMAGE ID CREATED + quay.io/blockstack/blockstack-browser v0.30.0 ad05fd844f59 3 days ago + $ sudo docker image rm ad05fd844f59
 + Untagged : quay.io/blockstack/blockstack- browser :vO.30.0 + Untagged: quay.io/blockstack/blockstack-browser@sha256:b20c9514c56b99398fd4946af39e7537b807e85694943ac3b8807dlb3625833b + Deleted: Sha256:ad05fd844f5948blee06a0a09228df946478393c0a7588cbc65dlb8817f5b34e + Deleted: Sha256:7c3d0043f2ba01cf285f3fe09701b086c349b6380c2e42f25b31ac65c6626ec8 + Deleted: sha256:54ea2aa7d7d000e7483f299eeca9e5466fa86231f4cd4cld3c3096d97e61c5df + Deleted: sha256:38e61054355adefc3c2de031462114a9946cfc0e44444a38a27d0f115aba0da2 + .... + ``` + +3. Use the script to remove the protocol handler + + ```bash + $ sudo ./Blockstack-for-Linux-vO.30.0.sh remove-protocol-handler + ``` + +4. Delete the script. + + ```bash + $ rm Blockstack-for-Linux-vO.30.0.sh + ``` diff --git a/_browser/.svn/pristine/63/6326880dd17c45162090e3bb4902adefbccfcb15.svn-base b/_browser/.svn/pristine/63/6326880dd17c45162090e3bb4902adefbccfcb15.svn-base new file mode 100644 index 00000000..cd6b3b6a Binary files /dev/null and b/_browser/.svn/pristine/63/6326880dd17c45162090e3bb4902adefbccfcb15.svn-base differ diff --git a/_browser/.svn/pristine/64/6462fdc5109daa02e29fbf38f8602f7425387275.svn-base b/_browser/.svn/pristine/64/6462fdc5109daa02e29fbf38f8602f7425387275.svn-base new file mode 100644 index 00000000..8fa411cb --- /dev/null +++ b/_browser/.svn/pristine/64/6462fdc5109daa02e29fbf38f8602f7425387275.svn-base @@ -0,0 +1,812 @@ +--- +layout: learn +permalink: /:collection/:path.html +--- +# Blockstack Storage Tutorial +{:.no_toc} + +In this tutorial, you build a micro-blogging application using multi-player Gaia +storage. Gaia is Blockstack's [decentralized high-performance storage +system](https://github.com/blockstack/gaia). The tutorial contains the following +topics: + +* TOC +{:toc} + +This tutorial does not teach you about authentication. That is covered in depth [in the hello-blockstack tutorial](hello-blockstack). + + + + +## About this tutorial and the prerequisites you need + +At minimum, Blockstack requires macOS High Sierra. This tutorial was written for +a user running macOS High Sierra 10.13.4. The application you build is a +React.js application that is completely decentralized and server-less. While +not strictly required to follow along, basic familiarity with React.js is +helpful. + +When complete, the app is capable of the following: + +- authenticating users using Blockstack +- posting new statuses +- displaying statuses in the user profile +- looking up the profiles and statuses of other users + +The basic identity and storage services are provided by `blockstack.js`. To test +the application, you need to have already [registered a Blockstack ID](ids-introduction). + +The tutorial relies on the `npm` dependency manager. Before you begin, verify +you have installed `npm` using the `which` command. + +```bash +$ which npm +/usr/local/bin/npm +``` + +If you don't find `npm` in your system, [install +it](https://www.npmjs.com/get-npm). Finally, if you get stuck at any point +while working on the tutorial, the completed [source code is available for +you](https://github.com/larrysalibra/publik) to check your work against. + +## Use npm to install Yeoman and the Blockstack App Generator + +You use `npm` to install Yeoman. Yeoman is a generic scaffolding system that +helps users rapidly start new projects and streamline the maintenance of +existing projects. + + +1. Install Yeoman. + + ```bash + npm install -g yo + ``` +2. Install the Blockstack application generator. + + ```bash + npm install -g generator-blockstack + ``` + + + +## Generate and launch the public application + +In this section, you build an initial React.js application called Publik. + +1. Create a the `publik` directory. + + ```bash + mkdir publik + ``` + +2. Change into your new directory. + + ```bash + cd publik + ``` + +3. Use Yeoman and the Blockstack application generator to create your initial `publik` application. + + ```bash + yo blockstack:react + ``` + + You should see several interactive prompts. + + ```bash + $ yo blockstack:react + ? ========================================================================== + We're constantly looking for ways to make yo better! + May we anonymously report usage statistics to improve the tool over time? + More info: https://github.com/yeoman/insight & http://yeoman.io + ========================================================================== No + + _-----_ ╭──────────────────────────╮ + | | │ Welcome to the │ + |--(o)--| │ Blockstack app │ + `---------´ │ generator! │ + ( _´U`_ ) ╰──────────────────────────╯ + /___A___\ / + | ~ | + __'.___.'__ + ´ ` |° ´ Y ` + + ? Are you ready to build a Blockstack app in React? (Y/n) + ``` + +4. Respond to the prompts to populate the initial app. + + After the process completes successfully, you see a prompt similar to the following: + + ```bash + [fsevents] Success: + "/Users/theuser/repos/publik/node_modules/fsevents/lib/binding/Release/node-v59-darwin-x64/fse.node" + is installed via remote npm notice created a lockfile as package-lock.json. + You should commit this file. added 1060 packages in 26.901s + ``` + +5. Run the initial application. + + ```bash + npm start + ``` + + The system prompts you to accept incoming connections. + + ![Network Connection](./images/network-connections.gif) + +6. Choose **Allow**. + +7. Open your browser to `http://localhost:8080`. + + You should see a simple React app. + + ![](images/initial-app.gif) + +8. Choose **Sign In with Blockstack**. + + The application tells you it will **Read your basic info**. + + ![](images/login.png) + +Leave your new application running and move onto the next section. + +## Add the `publish_data` scope to sign in requests + +Every app that uses Gaia storage must add itself to the user's `profile.json` +file. The Blockstack browser does this automatically when the `publish_data` +scope is requested during authentication. For this application, the user files +stored on Gaia are made visible to others via the `apps` property in the user's +`profile.json` file. + +Modify your authentication request to include the `publish_data` scope. + +1. Open `src/components/App.jsx` file. + +2. Locate the `handleSignIn` handler method. + + ```javascript + handleSignIn(e) { + e.preventDefault(); + redirectToSignIn(); + } + ``` + +2. Modify the method to this: + + ```javascript + handleSignIn(e) { + e.preventDefault(); + const origin = window.location.origin + redirectToSignIn(origin, origin + '/manifest.json', ['store_write', 'publish_data']) + } + ``` + + By default, authentication requests include the `store_write` scope which + enables storage. This is what allows you to store information to Gaia. + +3. Save your changes. +4. Go back to your app at `http://localhost:8080/`. +5. Log out and sign in again. + + The authentication request now prompts the user for permission to **Publish + data stored for the app**. + + ![](images/publish-data-perm.png) + +## Understand Gaia storage methods + +Once you authenticate a user with `store_write` and `publish_data`, you can +begin to manage data for your users. Blockstack JS provides two methods +`getFile()` and `putFile()` for interacting with Gaia storage. The storage +methods support all file types. This means you can store SQL, Markdown, JSON, or +even a custom format. + +You can create a meaningful and complex data layer using these two methods. +Before creating an application, consider fundamental data architecture and make +some decisions about how you’re modeling data. For example, consider building a +simple grocery list app. A user should be able to create, read, update, and +delete grocery lists. + +A single file collection stores items as an array nested inside each grocery +list: + +```js +// grocerylists.json +{ + "3255": { + "items": [ + "1 Head of Lettuce", + "Haralson apples" + ] + }, + // ...more lists with items +} +``` + +This is conceptually the simplest way to manage grocery lists. When you read a +`/grocerylists.json` file with `getFile()`, you get back one or more grocery +lists and their items. When you write a single list, the `putFile()` method +overwrites the entire list. So, a write operation for a new or updated grocery +list must submit all existings lists as well. + +Further, because this runs on the client where anything can go wrong. If the +client-side code encounters a parsing error with a user-input value and you +could overwrite the entire file with: + +`line 6: Parsing Error: Unexpected token.` + +Further, a single file makes pagination impossible and if your app stores a +single file for all list you have less control over file permissions. To avoid +these issues, you can create an index file that stores an array of IDs. These +IDs point to a name of another file in a `grocerylists` folder. + +![](images/multiple-lists.png) + +This design allows you to get only the files you need and avoid accidentally +overwriting all lists. Further, you’re only updating the index file when you add +or remove a grocery list; updating a list has no impact. + + +## Add support for user status submission and lookup + +In this step, you add three `blockstack.js` methods that support posting of "statuses". These are the `putFile()`, `getFile()`, and `lookupProfile()` methods. + +1. Open the `src/components/Profile.jsx` file. + +2. Expand the `import from blockstack` statement with data methods. + + The `Person` object holds a Blockstack profile. Add `putFile`, `getFile`, + and `lookupProfile` after `Person`. + + When you are done, the import statement should look like the following: + + ```javascript + import { + isSignInPending, + loadUserData, + Person, + getFile, + putFile, + lookupProfile + } from 'blockstack'; + ``` + +3. Replace the `constructor()` initial state so that it holds the key properties required by the app. + + This code constructs a Blockstack `Person` object to hold the profile. Your constructor should look like this: + + ```javascript + constructor(props) { + super(props); + + this.state = { + person: { + name() { + return 'Anonymous'; + }, + avatarUrl() { + return avatarFallbackImage; + }, + }, + username: "", + newStatus: "", + statuses: [], + statusIndex: 0, + isLoading: false + }; + } + ``` + + +4. Locate the `render()` method. +5. Modify the `render()` method to add a text input and submit button to the application. + + The following code echos the `person.name` and `person.avatarURL` + properties from the profile on the display: + + ```javascript + render() { + const { handleSignOut } = this.props; + const { person } = this.state; + const { username } = this.state; + + return ( + !isSignInPending() && person ? +
+
+
+
+
+ +
+

+ { person.name() ? person.name() + : 'Nameless Person' } +

+ {username} + +  |  + (Logout) + +
+
+
+ +
+
+