├── .gitignore ├── CHANGELOG.md ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── j2v8-debugger-sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── alexii │ │ └── j2v8debugging │ │ └── sample │ │ ├── App.kt │ │ ├── ExampleActivity.kt │ │ ├── SimpleScriptProvider.kt │ │ └── di │ │ ├── AppComponent.kt │ │ ├── AppModule.kt │ │ └── BuildersModule.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_example.xml │ └── content_example.xml │ ├── menu │ └── menu_example.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── j2v8-debugger ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── alexii │ │ │ └── j2v8debugger │ │ │ ├── CDPMethods.kt │ │ │ ├── Debugger.kt │ │ │ ├── Mappers.kt │ │ │ ├── Runtime.kt │ │ │ ├── ScriptSourceProvider.kt │ │ │ ├── StethoHelper.kt │ │ │ ├── V8Debugger.kt │ │ │ ├── V8Messenger.kt │ │ │ └── utils │ │ │ ├── LogUtils.kt │ │ │ └── Logger.kt │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ ├── java │ └── com │ │ └── alexii │ │ └── j2v8debugger │ │ ├── DebuggerTest.kt │ │ ├── MapperTests.kt │ │ ├── StethoHelperTest.kt │ │ └── utils │ │ └── LoggerTest.kt │ └── resources │ └── mockito-extensions │ └── org.mockito.plugins.MockMaker └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | 12 | #Mac folder files 13 | .DS_Store 14 | 15 | #idea and android studio files 16 | .idea 17 | 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | Version 0.2.4 5 | ---------------------------- 6 | * Switch from unmaintained Stetho to the maintained forked repo: https://github.com/yinyinnie/stetho 7 | * Allows editing JS code from Chrome dev tools 8 | * Fixes the states when debugger is stuck in paused state by adding some extra checks and resuming it if happens. 9 | 10 | 11 | Version 0.2.3 12 | ---------------------------- 13 | * Check if debugger has DevTools connection before sending messages from J2V8. If not, resume debugger (prevents getting stuck in paused state). 14 | 15 | Version 0.2.2 16 | ---------------------------- 17 | * Setting breakpoints during debugging (paused) doesn't kill DevTools. Next execution will pick up breakpoint. 18 | 19 | Version 0.2.1 20 | ---------------------------- 21 | * fixed unnecessary v8Executor.execute() in StethoHelper.bindV8ToChromeDebuggerIfReady() 22 | 23 | Version 0.2.0 24 | ---------------------------- 25 | * Updated V8 to 6.1.0 26 | * Replaced DebugHandler with V8Inspector 27 | * Removed backport (for v8 version below 4.8) 28 | 29 | Version 0.1.2 30 | ---------------------------- 31 | * Fixed not working debugger on older then 4.8 version of j2v8: separate j2v8backport module is created with j2v8 v4.6.0 as dependency. 32 | * j2v8backport is being published together with j2v8-debugger 33 | 34 | Version 0.1.1 35 | ---------------------------- 36 | * Do not skip debugging "pause" event if some V8 local variables can't be converted to Java and sent to Chrome Debugger 37 | * Added info about handled exception if debug event (break-point hit) can't be send to Chrome DevTools (Debugger UI) 38 | * Added ability to use j2v8-debugger lib with older then 4.8 version of j2v8: E.g. version 4.6 (latest published for mac and windows) 39 | * Added info about set-up, usage and known issues to Readme 40 | 41 | Version 0.1 42 | ---------------------------- 43 | Initial version with basic JS debugging functionality is implemented: 44 | * Debugging embedded V8 in Android app using Chrome DevTools. 45 | * Support setting/removing breakpoints, step into, step out and step over, variables inspection, etc. 46 | * Debugging embedded V8 is similar to [Remote Debugging WebViews](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews). 47 | * Access debuggable V8 in the app via **chrome://inspect**. 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # J2V8-Debugger 2 | 3 | This project is an add-on for the excellent [J2V8 Project](https://github.com/eclipsesource/J2V8). 4 | 5 | It allows users to debug JS running in V8 using [Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools/). 6 | 7 | Uses [Stetho](https://github.com/facebook/stetho) for communication with Chrome DevTools. 8 | 9 | ## Features 10 | * Debugging embedded V8 in Android app using Chrome DevTools. 11 | * Support setting/removing breakpoints, step into, step out and step over, variables inspection, etc. 12 | * Debugging embedded V8 is similar to [Remote Debugging WebViews](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews). 13 | * Access debuggable V8 in the app via **chrome://inspect**. 14 | 15 | ## SetUp 16 | Add JitPack repository in your root build.gradle at the end of repositories: 17 | 18 | ```gradle 19 | allprojects { 20 | repositories { 21 | maven { url "https://jitpack.io" } 22 | } 23 | } 24 | ``` 25 | 26 | Add dependency in *gradle.build* file of your app module 27 | ```gradle 28 | dependencies { 29 | implementation ('com.github.AlexTrotsenko:j2v8-debugger:0.2.4') // { 30 | // optionally J2V8 can be excluded if specific version of j2v8 is needed or defined by other libs 31 | // exclude group: 'com.eclipsesource.j2v8' 32 | // } 33 | } 34 | ``` 35 | 36 | **Note:** current `j2v8-debugger` version is designed for `J2V8` version _6.1+_. 37 | 38 | Use [0.1.2](https://github.com/AlexTrotsenko/j2v8-debugger/tree/0.1.2) when debugging of older J2V8 _(4.6.0+)_ is required. 39 | 40 | ## Usage 41 | 42 | `StethoHelper` and `V8Debugger` are used for set-up of Chrome DevTools and V8 for debugging. 43 | 44 | 1. Initialization Stetho in `Application` class. 45 | 46 | ```.Kotlin 47 | StethoHelper.initializeDebugger(context, scriptSourceProvider) 48 | ``` 49 | 50 | 2. Creation of debuggable V8 instance. 51 | 52 | Use `V8Debugger.createDebuggableV8Runtime()` instead of `V8.createV8Runtime()` 53 | 54 | ```.Kotlin 55 | val debuggableV8Runtime : Future = V8Debugger.createDebuggableV8Runtime(v8Executor, globalAlias, enableLogging) 56 | ``` 57 | 58 | See [sample project](https://github.com/AlexTrotsenko/j2v8-debugger/blob/master/j2v8-debugger-sample/src/main/java/com/alexii/j2v8debugging/sample/ExampleActivity.kt) for more info. 59 | 60 | ### Notes regarding J2V8 threads. 61 | - Creation and clean-up of V8 should run on fixed V8 thread. 62 | - Creation and clean-up of V8 Debugger should run on fixed V8 thread. 63 | - Debugging operation like set/remove breakpoint should run on fixed V8 thread. 64 | - Execution of any JS script/function should run on fixed V8 thread. 65 | 66 | It's easier to implement such behaviour _(especially from lib point of view)_ if single-threaded V8 executor is used. 67 | 68 | This way all above mentioned operations would run on such executor. 69 | 70 | Therefore lib api like `V8Debugger.createDebuggableV8Runtime(v8Executor)` is build with this concept in mind. 71 | 72 | Later v8 executor will be passed to Chrome DevTools and used for performing debug-related operations. 73 | 74 | If Guava is already used in project - MoreExecutors and [ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained) could be handy. 75 | 76 | ### License 77 | 78 | ``` 79 | Copyright 2015 Alexii Trotsenko 80 | 81 | Licensed under the Apache License, Version 2.0 (the "License"); 82 | you may not use this file except in compliance with the License. 83 | You may obtain a copy of the License at 84 | 85 | http://www.apache.org/licenses/LICENSE-2.0 86 | 87 | Unless required by applicable law or agreed to in writing, software 88 | distributed under the License is distributed on an "AS IS" BASIS, 89 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 90 | See the License for the specific language governing permissions and 91 | limitations under the License. 92 | ``` 93 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | kotlin_version = "1.3.72" 6 | } 7 | 8 | repositories { 9 | google() 10 | jcenter() 11 | maven { url "https://jitpack.io" } 12 | } 13 | dependencies { 14 | classpath "com.android.tools.build:gradle:4.0.0" 15 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 16 | classpath "com.github.dcendents:android-maven-gradle-plugin:2.1" 17 | 18 | // NOTE: Do not place your application dependencies here; they belong 19 | // in the individual module build.gradle files 20 | } 21 | } 22 | 23 | allprojects { 24 | version = VERSION_NAME 25 | 26 | repositories { 27 | google() 28 | jcenter() 29 | maven { url "https://jitpack.io" } 30 | } 31 | } 32 | 33 | subprojects { 34 | group = GROUP_NAME 35 | } 36 | 37 | task clean(type: Delete) { 38 | delete rootProject.buildDir 39 | } 40 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | #Explicitly enable "Kotlin Coding Conventions" instead of "IntelliJ IDEA default code style" 16 | kotlin.code.style=official 17 | 18 | #publishing settings for Gradle build script 19 | VERSION_NAME=0.2.4 20 | #make group name of local build to be the same as by JitPack builds 21 | GROUP_NAME=com.github.AlexTrotsenko 22 | android.useAndroidX=true 23 | android.enableJetifier=true 24 | kapt.incremental.apt=true 25 | kapt.use.worker.api=true 26 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | 6 | android { 7 | compileSdkVersion 28 8 | defaultConfig { 9 | applicationId "com.alexii.j2v8debugging" 10 | minSdkVersion 23 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | dataBinding{ 28 | enabled = true 29 | } 30 | } 31 | 32 | ext { 33 | daggerVersion = "2.16" 34 | } 35 | 36 | dependencies { 37 | implementation project(path: ':j2v8-debugger') 38 | 39 | implementation fileTree(dir: 'libs', include: ['*.jar']) 40 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version") 41 | implementation('androidx.appcompat:appcompat:1.1.0') 42 | implementation('androidx.constraintlayout:constraintlayout:1.1.3') 43 | implementation('com.google.android.material:material:1.1.0') 44 | implementation("com.google.guava:guava:25.1-android") 45 | 46 | // Dagger core 47 | implementation("com.google.dagger:dagger:$daggerVersion") 48 | kapt("com.google.dagger:dagger-compiler:$daggerVersion") 49 | 50 | // Dagger Android 51 | implementation("com.google.dagger:dagger-android:$daggerVersion") 52 | implementation("com.google.dagger:dagger-android-support:$daggerVersion") 53 | kapt("com.google.dagger:dagger-android-processor:$daggerVersion") 54 | 55 | implementation("com.jakewharton.timber:timber:4.7.1") 56 | } 57 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/java/com/alexii/j2v8debugging/sample/App.kt: -------------------------------------------------------------------------------- 1 | package com.alexii.j2v8debugging.sample 2 | 3 | import android.app.Activity 4 | import android.app.Application 5 | import com.alexii.j2v8debugger.ScriptSourceProvider 6 | import com.alexii.j2v8debugger.StethoHelper 7 | import com.alexii.j2v8debugging.sample.di.DaggerAppComponent 8 | import dagger.android.AndroidInjector 9 | import dagger.android.DispatchingAndroidInjector 10 | import dagger.android.HasActivityInjector 11 | import timber.log.Timber 12 | import javax.inject.Inject 13 | 14 | class App : Application(), HasActivityInjector { 15 | @Inject 16 | lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector 17 | 18 | @Inject 19 | lateinit var scriptProvider: ScriptSourceProvider 20 | 21 | override fun onCreate() { 22 | super.onCreate() 23 | Timber.plant(Timber.DebugTree()) 24 | 25 | DaggerAppComponent 26 | .builder() 27 | .application(this) 28 | .build() 29 | .inject(this) 30 | 31 | StethoHelper.initializeDebugger(this, scriptProvider) 32 | 33 | Timber.w("[Alex_Stetho] initialize") 34 | } 35 | 36 | override fun activityInjector(): AndroidInjector? { 37 | return dispatchingAndroidInjector 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/java/com/alexii/j2v8debugging/sample/ExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.alexii.j2v8debugging.sample 2 | 3 | import android.os.Bundle 4 | import android.view.Menu 5 | import android.view.MenuItem 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.alexii.j2v8debugger.StethoHelper 8 | import com.alexii.j2v8debugger.V8Debugger 9 | import com.alexii.j2v8debugging.R 10 | import com.eclipsesource.v8.V8 11 | import com.google.android.material.snackbar.Snackbar 12 | import dagger.android.AndroidInjection 13 | import kotlinx.android.synthetic.main.activity_example.fab 14 | import kotlinx.android.synthetic.main.activity_example.toolbar 15 | import java.util.Random 16 | import java.util.concurrent.ExecutorService 17 | import java.util.concurrent.Future 18 | import javax.inject.Inject 19 | 20 | class ExampleActivity : AppCompatActivity() { 21 | @Inject 22 | lateinit var simpleScriptProvider: SimpleScriptProvider 23 | 24 | /** V8 should be initialized and further called on the same thread.*/ 25 | @Inject 26 | lateinit var v8Executor: ExecutorService 27 | 28 | lateinit var v8Future: Future 29 | 30 | /** Must be called only in v8's thread only. */ 31 | private val v8: V8 by lazy { v8Future.get() } 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | val scriptName = "hello-world" 35 | var scriptPostfix = 1 36 | AndroidInjection.inject(this) 37 | updateUserToRandom() 38 | v8Future = initDebuggableV8() 39 | 40 | super.onCreate(savedInstanceState) 41 | setContentView(R.layout.activity_example) 42 | setSupportActionBar(toolbar) 43 | 44 | fab.setOnClickListener { view -> 45 | scriptPostfix = 1 - scriptPostfix 46 | val scriptToDebug = "${scriptName}${scriptPostfix}" 47 | val jsScript = simpleScriptProvider.getSource(scriptToDebug) 48 | 49 | v8Executor.submit { 50 | val result = v8.executeScript(jsScript, scriptToDebug, 0) 51 | println("[v8 execution result: ] $result") 52 | 53 | Snackbar.make(view, "V8 answers: $result", Snackbar.LENGTH_SHORT) 54 | .setAction("V8Action", null).show() 55 | } 56 | } 57 | } 58 | 59 | private fun initDebuggableV8(): Future { 60 | return V8Debugger.createDebuggableV8Runtime(v8Executor, "demo", true) 61 | } 62 | 63 | override fun onDestroy() { 64 | releaseDebuggableV8() 65 | 66 | super.onDestroy() 67 | } 68 | 69 | private fun releaseDebuggableV8() { 70 | v8Executor.execute { 71 | v8.close() 72 | } 73 | } 74 | 75 | private fun updateUserToRandom() { 76 | val newUser = "user" + Random().nextInt(10) 77 | //following assumes, that some JS sources are different per user 78 | StethoHelper.scriptsPathPrefix = newUser 79 | } 80 | 81 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 82 | // Inflate the menu; this adds items to the action bar if it is present. 83 | menuInflater.inflate(R.menu.menu_example, menu) 84 | return true 85 | } 86 | 87 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 88 | // Handle action bar item clicks here. The action bar will 89 | // automatically handle clicks on the Home/Up button, so long 90 | // as you specify a parent activity in AndroidManifest.xml. 91 | return when (item.itemId) { 92 | R.id.action_scripts_changed -> { 93 | simpleScriptProvider.updateTimeToNow() 94 | StethoHelper.notifyScriptsChanged() 95 | true 96 | } 97 | R.id.action_user_and_scripts_changed -> { 98 | //here user and related scripts should be changed 99 | updateUserToRandom() 100 | simpleScriptProvider.updateTimeToNow() 101 | StethoHelper.notifyScriptsChanged() 102 | true 103 | } 104 | else -> super.onOptionsItemSelected(item) 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/java/com/alexii/j2v8debugging/sample/SimpleScriptProvider.kt: -------------------------------------------------------------------------------- 1 | package com.alexii.j2v8debugging.sample 2 | 3 | import com.alexii.j2v8debugger.ScriptSourceProvider 4 | import java.text.DateFormat 5 | import java.util.Date 6 | import javax.inject.Inject 7 | import javax.inject.Singleton 8 | 9 | @Singleton 10 | class SimpleScriptProvider @Inject constructor() : ScriptSourceProvider { 11 | 12 | private val scriptName = "hello-world" 13 | private lateinit var dateString: String 14 | 15 | init { 16 | updateTimeToNow() 17 | } 18 | 19 | fun updateTimeToNow() { 20 | dateString = DateFormat.getTimeInstance().format(Date()) 21 | } 22 | 23 | override val allScriptIds = listOf("${scriptName}0", "${scriptName}1") 24 | 25 | override fun getSource(scriptId: String): String { 26 | val jsScript = (""" 27 | |var globalHi = "hi from $scriptId" 28 | | 29 | |function main(payloadObject) { 30 | | var hello = 'hello, '; 31 | | var world = 'world'; 32 | | 33 | | var testReload = '$dateString'; 34 | | 35 | | return globalHi + ' and ' + hello + world + ' at ' + testReload + ' with ' + payloadObject.load + ' !'; 36 | |} 37 | | 38 | |main({ 39 | | load: 'object based payload', 40 | | redundantLoad: 'this is ignored', 41 | | callBack: function testCallBack() { print('Call back!') } 42 | |}) 43 | """).trimMargin() 44 | 45 | return jsScript 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/java/com/alexii/j2v8debugging/sample/di/AppComponent.kt: -------------------------------------------------------------------------------- 1 | package com.alexii.j2v8debugging.sample.di 2 | 3 | import com.alexii.j2v8debugging.sample.App 4 | import dagger.BindsInstance 5 | import dagger.Component 6 | import dagger.android.support.AndroidSupportInjectionModule 7 | import javax.inject.Singleton 8 | 9 | @Singleton 10 | @Component(modules = arrayOf(AndroidSupportInjectionModule::class, AppModule::class, BuildersModule::class)) 11 | interface AppComponent { 12 | @Component.Builder 13 | interface Builder { 14 | @BindsInstance 15 | fun application(application: App): Builder 16 | 17 | fun build(): AppComponent 18 | } 19 | 20 | fun inject(app: App) 21 | } 22 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/java/com/alexii/j2v8debugging/sample/di/AppModule.kt: -------------------------------------------------------------------------------- 1 | package com.alexii.j2v8debugging.sample.di 2 | 3 | import android.content.Context 4 | import com.alexii.j2v8debugger.ScriptSourceProvider 5 | import com.alexii.j2v8debugging.sample.App 6 | import com.alexii.j2v8debugging.sample.SimpleScriptProvider 7 | import dagger.Binds 8 | import dagger.Module 9 | import dagger.Provides 10 | import java.util.concurrent.ExecutorService 11 | import java.util.concurrent.Executors 12 | import javax.inject.Singleton 13 | 14 | /** 15 | * This is where you will inject application-wide dependencies. 16 | */ 17 | @Module(includes = [AppModule.Declarations::class]) 18 | class AppModule { 19 | 20 | @Module 21 | interface Declarations { 22 | @Binds 23 | fun provideContext(application: App): Context 24 | 25 | @Binds 26 | fun provideSimpleScriptProvider(simpleScriptProvider: SimpleScriptProvider): ScriptSourceProvider 27 | } 28 | 29 | @Singleton 30 | @Provides 31 | fun provideScriptSourceProvider(): SimpleScriptProvider { 32 | return SimpleScriptProvider() 33 | } 34 | 35 | @Singleton 36 | @Provides 37 | fun provideV8ExecutorService(): ExecutorService { 38 | return Executors.newSingleThreadExecutor(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/java/com/alexii/j2v8debugging/sample/di/BuildersModule.kt: -------------------------------------------------------------------------------- 1 | package com.alexii.j2v8debugging.sample.di 2 | 3 | import com.alexii.j2v8debugging.sample.ExampleActivity 4 | 5 | import dagger.Module 6 | import dagger.android.ContributesAndroidInjector 7 | 8 | /** 9 | * Binds sub-components within the app. 10 | */ 11 | @Module 12 | abstract class BuildersModule { 13 | 14 | @ContributesAndroidInjector 15 | internal abstract fun bindExampleActivity(): ExampleActivity 16 | } 17 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/layout/activity_example.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/layout/content_example.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/menu/menu_example.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexTrotsenko/j2v8-debugger/aad62fa4f8a309913ca0324e736d2f0e2f53508c/j2v8-debugger-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 4 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | J2V8DebugExample 3 | Notify Scripts Changed 4 | Update user and related scripts 5 | 6 | -------------------------------------------------------------------------------- /j2v8-debugger-sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |