diff --git a/demos/android/.gitignore b/demos/android/.gitignore index 0718494ec..0d7a3d8a8 100644 --- a/demos/android/.gitignore +++ b/demos/android/.gitignore @@ -1,5 +1,6 @@ /build /captures +/app/src/main/assets/blockly/msg .settings .project diff --git a/demos/android/README.md b/demos/android/README.md new file mode 100644 index 000000000..9c63f70b6 --- /dev/null +++ b/demos/android/README.md @@ -0,0 +1,45 @@ +# Blockly in an Android WebView + +This code demonstrates how to get Blockly running in an Android app by +embedding it in a WebView. + +### BlocklyWebViewFragment + +Most of the work is done within the fragment class `BlocklyWebViewFragment`. +This fragment instantiates the WebView, loads the HTML +(`assets/blockly/webview.html`), and provides a few helper methods. + +### Copying web assets with gradle + +This android project copies the necessary files from the main Blockly +repository (i.e., parent directory). In `app/build.gradle`, note the +`copyBlocklyWebFiles` task and `preBuild.dependsOn copyBlocklyWebFiles` line. + +In your own project, these files can be placed directly in the `assets/blockly` +directory without the copy step. However, if you do use the copy step, make +sure you adapt the copy paths appropriately. Additionally, you may want to +update your `.gitignore` or similar file. + +### Loading Block Definitions and Generator functions + +The `webview.html` loads the block definitions and generator functions directly +into the page, without support or coordination with the Android classes. This +assumes the app will always utilize the same blocks. This does not mean all +blocks are visible to the user all the time; that is controlled by the toolbox +and workspace files. This should accommodate almost all applications. + +This does mean loading your own block definitions and generators will involve +editing the HTML, adding you own `<script>` tag, and possibly removing +the `blocks_compressed.js` if you do not use any standard blocks. + +### Connecting a Developer Console + +While the console output of the WebView will be visible in the Android log +(i.e., `logcat`), some times a more intrusive approach is required to isolate +a problem. For instructions on connecting the WebView to Chrome's Developer +Tools, see this article: + + https://developers.google.com/web/tools/chrome-devtools/remote-debugging/ + +The WebView must be visible in the connect device or emulator before the +WebView will included in the list of available pages to connect to. \ No newline at end of file diff --git a/demos/android/app/.gitignore b/demos/android/app/.gitignore index 796b96d1c..d67f7b424 100644 --- a/demos/android/app/.gitignore +++ b/demos/android/app/.gitignore @@ -1 +1,6 @@ /build + +# Files copied during build: +src/main/assets/blockly/blockly_compressed.js +src/main/assets/blockly/blocks_compressed.js +src/main/assets/blockly/media diff --git a/demos/android/app/build.gradle b/demos/android/app/build.gradle index e80e4cbce..661a3db87 100644 --- a/demos/android/app/build.gradle +++ b/demos/android/app/build.gradle @@ -20,6 +20,18 @@ android { } } +task copyBlocklyWebFiles(type: Copy) { + from('../../..') { + include 'blockly_compressed.js', 'blocks_compressed.js', 'msg/js/**', 'media/**' + exclude 'media/test_*' + } + into project(':app').file('./src/main/assets/blockly') +} + +project.afterEvaluate { + preBuild.dependsOn copyBlocklyWebFiles +} + dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:27.1.1' diff --git a/demos/android/app/src/main/assets/blockly/toolbox_standard.js b/demos/android/app/src/main/assets/blockly/toolbox_standard.js new file mode 100644 index 000000000..77e1a6863 --- /dev/null +++ b/demos/android/app/src/main/assets/blockly/toolbox_standard.js @@ -0,0 +1,333 @@ + +var BLOCKLY_TOOLBOX_XML = BLOCKLY_TOOLBOX_XML || Object.create(null); + +/* BEGINNING BLOCKLY_TOOLBOX_XML ASSIGNMENT. DO NOT EDIT. USE BLOCKLY DEVTOOLS. */ +BLOCKLY_TOOLBOX_XML['standard'] = +// From XML string/file, replace ^\s?(\s*)?(<.*>)$ with \+$1'$2' +// Tweak first and last line. +'' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '10' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '1' ++ '' ++ '' ++ '' ++ '' ++ '10' ++ '' ++ '' ++ '' ++ '' ++ '1' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '123' ++ '' ++ '' ++ '' ++ '' ++ '1' ++ '' ++ '' ++ '' ++ '' ++ '1' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '9' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '45' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '0' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '3.1' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '64' ++ '' ++ '' ++ '' ++ '' ++ '10' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '50' ++ '' ++ '' ++ '' ++ '' ++ '1' ++ '' ++ '' ++ '' ++ '' ++ '100' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '1' ++ '' ++ '' ++ '' ++ '' ++ '100' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'abc' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'text' ++ '' ++ '' ++ '' ++ '' ++ 'abc' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'text' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'text' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'abc' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'abc' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'abc' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'abc' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '5' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'list' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'list' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'list' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ 'list' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ ',' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '100' ++ '' ++ '' ++ '' ++ '' ++ '50' ++ '' ++ '' ++ '' ++ '' ++ '0' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '#ff0000' ++ '' ++ '' ++ '' ++ '' ++ '#3333ff' ++ '' ++ '' ++ '' ++ '' ++ '0.5' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ '' ++ ''; +/* END BLOCKLY_TOOLBOX_XML ASSIGNMENT. DO NOT EDIT. */ diff --git a/demos/android/app/src/main/assets/blockly/webview.html b/demos/android/app/src/main/assets/blockly/webview.html new file mode 100644 index 000000000..0ecbea2f1 --- /dev/null +++ b/demos/android/app/src/main/assets/blockly/webview.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/demos/android/app/src/main/java/com/google/blockly/android/webview/BlocklyWebViewFragment.java b/demos/android/app/src/main/java/com/google/blockly/android/webview/BlocklyWebViewFragment.java new file mode 100644 index 000000000..c9629d2f3 --- /dev/null +++ b/demos/android/app/src/main/java/com/google/blockly/android/webview/BlocklyWebViewFragment.java @@ -0,0 +1,37 @@ +package com.google.blockly.android.webview; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebSettings; +import android.webkit.WebView; + +/** + * This fragments contains and manages the web view that hosts Blockly. + */ +public class BlocklyWebViewFragment extends Fragment { + protected @Nullable WebView mWebView = null; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + mWebView = new WebView(inflater.getContext()); + WebSettings webSettings = mWebView.getSettings(); + webSettings.setJavaScriptEnabled(true); + mWebView.loadUrl("file:///android_asset/blockly/webview.html"); + return mWebView; + } + + // TODO: Method to invoke code generation + // TODO: Method to load workspace from string (or InputStream?) + // TODO: Method to serialize workspace to string (or OutputStream?) + // TODO: Clear / reset workspace + // TODO: Load toolbox + // TODO: Listener for event JSON + // TODO: Method to evaluate JavaScript string in the WebView +} diff --git a/demos/android/app/src/main/java/com/google/blockly/android/webview/demo/MainActivity.java b/demos/android/app/src/main/java/com/google/blockly/android/webview/demo/MainActivity.java index 58cb54d92..ea7bf5659 100644 --- a/demos/android/app/src/main/java/com/google/blockly/android/webview/demo/MainActivity.java +++ b/demos/android/app/src/main/java/com/google/blockly/android/webview/demo/MainActivity.java @@ -5,8 +5,11 @@ import android.os.Bundle; import com.example.blocklywebview.R; +/** + * The primary activity of the demo application. The activity embeds the + * {@link com.google.blockly.android.webview.BlocklyWebViewFragment}. + */ public class MainActivity extends AppCompatActivity { - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/demos/android/app/src/main/res/layout/activity_main.xml b/demos/android/app/src/main/res/layout/activity_main.xml index 3dc9926ad..37dc152b0 100644 --- a/demos/android/app/src/main/res/layout/activity_main.xml +++ b/demos/android/app/src/main/res/layout/activity_main.xml @@ -7,13 +7,11 @@ android:layout_height="match_parent" tools:context="com.google.blockly.android.webview.demo.MainActivity"> - + \ No newline at end of file