├── .gitignore ├── 20190918135108.jpg ├── README.md ├── app ├── build.gradle ├── libs │ └── j2v8-5.0.103.aar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── tang │ │ └── test │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── j2v8 │ │ │ └── j2v8test.js │ ├── java │ │ └── com │ │ │ └── tang │ │ │ └── test │ │ │ ├── AsyncTaskBackListener.java │ │ │ ├── J2V8ReadJavaScript.java │ │ │ ├── MainActivity.java │ │ │ └── j2v8 │ │ │ ├── J2V8Helper.java │ │ │ ├── J2V8Interface.java │ │ │ ├── J2V8InterfaceImpl.java │ │ │ ├── J2V8Single.java │ │ │ ├── J2V8Util.java │ │ │ ├── J2V8ValueCallBack.java │ │ │ ├── J2v8Example.java │ │ │ ├── JavaCallbackImpl.java │ │ │ └── JavaVoidCallbackImpl.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.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 │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── tang │ └── test │ └── ExampleUnitTest.java ├── build.gradle ├── j2v8test.js └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | gradle/ 4 | .idea/ 5 | /app/build 6 | /gradle.properties 7 | /local.properties 8 | /gradlew 9 | /gradlew.bat 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /20190918135108.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangbei/j2v8_android/fa62ecda32bd35107287936e153459b46f297dea/20190918135108.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # j2v8的android测试demo。 2 | 3 | 本工程只是 j2v8 测试demo, 包含了j2v8的所有使用方法。可以下载 工程体验。 4 | 5 | #### j2v8使用方式: 6 | 1. 在build.gradle中添加依赖: 7 | ```java 8 | dependencies { 9 | compile 'com.eclipsesource.j2v8:j2v8:5.0.103@aar' 10 | } 11 | ``` 12 | 2. 也可以在app的libs中引入j2v8.aar文件。[点击获取maven地址](https://mvnrepository.com/artifact/com.eclipsesource.j2v8/j2v8) 13 | 同时在build.gradle中引入: 14 | ``` 15 | repositories { 16 | flatDir { 17 | dirs 'libs' 18 | } 19 | } 20 | ``` 21 | 22 | #### 后台java使用方式: 23 | 24 | maven依赖方式: 25 | ```maven 26 | 27 | com.eclipsesource.j2v8 28 | j2v8 29 | 5.0.103 30 | 31 | ``` 32 | java后台使用方式,和android类似,只是其中的j2v8方法还有使用上的区别。 33 | 34 | #### 工程demo使用介绍: 35 | 36 | 本工程已经包含了 所有j2v8使用到的方法,和使用到的工具类。以及包含了三种读取 js 文件的方式,方便在任何场景下 java 和 js的交互。 37 | 38 | #### 一、本地 js文件/js字符串 读取方式 39 | 40 | 在主工程app的assets文件夹中添加js脚本文件,如果没有assets文件夹,则新建一个。 41 | ![image](https://github.com/tangbei/j2v8_android/blob/master/20190918135108.jpg) 42 | 43 | 获取js脚本文件的方式: 44 | ``` 45 | final InputStream INPUTSTREAM = this.activity.getClass().getResourceAsStream("/assets/j2v8/j2v8test.js");//获取js脚本的输入流 46 | ``` 47 | 48 | #### 二、后台数据库js的string字符串 读取方式 49 | 50 | 在需要调取js的类中 implements J2V8Interface这个接口,同时实现 getJs()方法。 51 | ```java 52 | /** 53 | * js脚本 字符串 54 | * @return 55 | */ 56 | @Override 57 | public String getJs() { 58 | /* String s = "function j2v8String(x,y){\n" + 59 | " var name3 = x.concat(y);\n" + 60 | " return name3;\n" + 61 | "}";*/ 62 | return ""; 63 | } 64 | ``` 65 | 66 | 此读取方式,更加灵活,可以直接把js存到后台数据库,每次调用的时候 拿到后台的js字符串即可。 67 | 同时调用`J2V8Helper.class`暴露的帮助实现方法 即可,demo写的很详细,一些方法还是比较全面的,同时你可以自己更改代码,获取自己想要的实现方式,并放在自己的工程中。 具体可下载工程查看使用方式。 /n 68 | 69 | 注意事项:**存的是js脚本字符串、或者js脚本字符串方法**。 70 | 71 | 72 | #### 三、服务器js文件 读取方式 73 | 74 | js文件既可以本地读取,那么 服务器链接 读取肯定也是可以的。 75 | 76 | ```java 77 | /** 78 | * 获取oss上的js文件,并转换成String返回 79 | * 如果是获取网络地址,则使用 J2V8Single.class 处理 80 | * @param _url oss上的js地址:https://github.com/tangbei/j2v8_android/blob/master/j2v8test.js 81 | * @return 82 | */ 83 | public static String getOssJsUrl(String _url){ 84 | String jsPath =""; 85 | try { 86 | // 构造URL 87 | URL url = new URL(_url); 88 | // 打开连接 89 | URLConnection con = url.openConnection(); 90 | // 设置请求超时为5s 91 | con.setConnectTimeout(5 * 1000); 92 | // 输入流 93 | InputStream is = con.getInputStream(); 94 | jsPath = supplyAsync(is); 95 | is.close(); 96 | } catch (Exception e) { 97 | e.printStackTrace(); 98 | } 99 | return jsPath; 100 | } 101 | ``` 102 | 103 | 但是调取方式和第一种不同,是在 `J2V8Single.class`单例类中使用,目的是只网络读取一遍js脚本文件。 104 | 105 | 106 | #### 读取方式优劣分析 107 | 1. 三种方式在读取上第二种是最快的,直接拿到的是js脚本字符串。 108 | 2. 本地读取和本地读取字符串也是最快、但是不可动态配置js脚本,不灵活。 109 | 3. 服务器读取虽然动态可配置,但是读取速度上不占优,使用单例模式加载网络文件,目的是使用时只读取一遍,提升代码可用度。 110 | 111 | 综上,还是推荐数据库存储js字符串 读取、即可动态配置、也不失灵活、读取便捷、扩展性强、适用场景更多。 112 | 113 | 114 | 115 | #### 注意事项 116 | 1. 本demo只是粗略概括了`j2v8`的各种使用方式,为初次使用 jav8 的人搭个桥。 117 | 2. 使用j2v8时一定要及时释放,否则会很耗性能和内存。 118 | 3. 如果java后台使用j2v8 也可以使用此demo,只是依赖替换一下,具体使用大同小异。 119 | 4. 本demo,可以随意更改,并用到自己的工程中,希望能帮到你们。 120 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.tang.test" 7 | minSdkVersion 14 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | repositories { 22 | flatDir { 23 | dirs 'libs' 24 | } 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(dir: 'libs', include: ['*.jar']) 29 | implementation 'com.android.support:appcompat-v7:28.0.0' 30 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 31 | 32 | implementation (name: 'j2v8-5.0.103',ext: 'aar') 33 | 34 | testImplementation 'junit:junit:4.12' 35 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 36 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 37 | } 38 | -------------------------------------------------------------------------------- /app/libs/j2v8-5.0.103.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangbei/j2v8_android/fa62ecda32bd35107287936e153459b46f297dea/app/libs/j2v8-5.0.103.aar -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/tang/test/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.tang.test; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.tang.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/assets/j2v8/j2v8test.js: -------------------------------------------------------------------------------- 1 | 2 | function j2v8String(x,y){ 3 | 4 | 5 | var name3 = x.concat(y); 6 | return name3; 7 | } 8 | 9 | function j2v8Int(x,y){ 10 | 11 | var name3 = x + y; 12 | return name3; 13 | } 14 | 15 | function j2v8Boolean(x,y){ 16 | 17 | return x == y; 18 | } 19 | 20 | function putVoid(x,y){ 21 | var array = [{name:'zhangSan'}, {name:'liSi'}, {name:'wangMaZi'}]; 22 | for ( var i = 0; i < array.length; i++ ) { 23 | javaVoid.call(array[i], " 你好啊"); // javaVoid 是 java 注册到 js 的一个函数 24 | } 25 | return j2v8Int(x,y); 26 | } 27 | 28 | var j2v8New = { 29 | a: "111", 30 | b: "222" 31 | }; 32 | 33 | function handle(x,y,callBack){ 34 | callBack(x+y); 35 | } 36 | 37 | function javaCallBack(x,y){ 38 | 39 | var t = javaBack(x+y);//javaBack是 java注册到js中的一个回调函数 40 | return t; 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/AsyncTaskBackListener.java: -------------------------------------------------------------------------------- 1 | package com.tang.test; 2 | 3 | /** 4 | * 描述: 5 | * 作者 : Tong 6 | * e-mail : itangbei@sina.com 7 | * 创建时间: 2019/8/5. 8 | */ 9 | public interface AsyncTaskBackListener { 10 | 11 | void onAsyncTaskCallBack(T t); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/J2V8ReadJavaScript.java: -------------------------------------------------------------------------------- 1 | package com.tang.test; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.res.AssetManager; 6 | import android.os.AsyncTask; 7 | 8 | import com.tang.test.j2v8.J2V8Util; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | 15 | /** 16 | * 描述: 使用asyncTask异步读取本地js脚本 17 | * 作者 : Tong 18 | * e-mail : itangbei@sina.com 19 | * 创建时间: 2019/8/5. 20 | */ 21 | public class J2V8ReadJavaScript extends AsyncTask 22 | { 23 | private AsyncTaskBackListener listener; 24 | 25 | private Activity activity; 26 | public J2V8ReadJavaScript(Activity activity, AsyncTaskBackListener listener) 27 | { 28 | this.listener = listener; 29 | this.activity = activity; 30 | 31 | } 32 | public J2V8ReadJavaScript() 33 | { 34 | super(); 35 | } 36 | 37 | @Override 38 | protected String doInBackground(String... strparams) 39 | { 40 | final InputStream INPUTSTREAM = this.activity.getClass().getResourceAsStream("/assets/j2v8/j2v8test.js");//获取js脚本的输入流 41 | return J2V8Util.getFileContent(INPUTSTREAM); 42 | } 43 | @Override 44 | protected void onPostExecute(String result) 45 | { 46 | if (listener != null) 47 | { 48 | listener.onAsyncTaskCallBack(result); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.tang.test; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import com.eclipsesource.v8.JavaCallback; 10 | import com.eclipsesource.v8.JavaVoidCallback; 11 | import com.eclipsesource.v8.V8; 12 | import com.eclipsesource.v8.V8Array; 13 | import com.eclipsesource.v8.V8Function; 14 | import com.eclipsesource.v8.V8Object; 15 | import com.tang.test.j2v8.J2V8Helper; 16 | import com.tang.test.j2v8.J2V8Interface; 17 | import com.tang.test.j2v8.J2V8InterfaceImpl; 18 | import com.tang.test.j2v8.J2V8Util; 19 | import com.tang.test.j2v8.J2V8ValueCallBack; 20 | import com.tang.test.j2v8.J2v8Example; 21 | import com.tang.test.j2v8.JavaCallbackImpl; 22 | import com.tang.test.j2v8.JavaVoidCallbackImpl; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | public class MainActivity extends AppCompatActivity implements J2V8Interface { 28 | 29 | private TextView tvContent; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_main); 35 | 36 | tvContent = findViewById(R.id.tv_content); 37 | } 38 | 39 | 40 | public void jav8OnClick(View view){ 41 | // localRead(); 42 | 43 | readJs(); 44 | } 45 | 46 | private void localRead(){ 47 | 48 | J2v8Example.getJs(this,new JavaCallbackImpl(),new JavaVoidCallbackImpl(),new J2V8ValueCallBack() { 49 | @Override 50 | public void getReadValue(String value) { 51 | tvContent.setText(value); 52 | } 53 | }); 54 | } 55 | 56 | /** 57 | * js脚本 字符串 58 | * @return 59 | */ 60 | @Override 61 | public String getJs() { 62 | /* String s = "function j2v8String(x,y){\n" + 63 | " var name3 = x.concat(y);\n" + 64 | " return name3;\n" + 65 | "}";*/ 66 | return ""; 67 | } 68 | 69 | private void readJs(){ 70 | List list = new ArrayList<>(); 71 | list.add("我是j2v8Helper调取的 参数1,"); 72 | list.add("我是j2v8Helper调取的 参数2"); 73 | String jsString = J2V8Helper.engineJs(this,"j2v8String",list); 74 | tvContent.setText(jsString); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/J2V8Helper.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | import android.app.Activity; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import com.eclipsesource.v8.JavaVoidCallback; 8 | import com.eclipsesource.v8.V8; 9 | import com.tang.test.AsyncTaskBackListener; 10 | import com.tang.test.J2V8ReadJavaScript; 11 | import com.tang.test.MainActivity; 12 | 13 | import java.io.InputStream; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * 描述: j2v8帮助实现类 19 | * 作者 : Tong 20 | * e-mail : itangbei@sina.com 21 | * 创建时间: 2019/8/28. 22 | */ 23 | public class J2V8Helper { 24 | 25 | /** 26 | * 获取js解析后的数据 27 | * @param context 上下文 28 | * @param convertName js的处理方法 29 | * @return js解析处理后的数据 30 | */ 31 | public static String engineJs(J2V8Interface context,String convertName){ 32 | return engineJs(context,convertName,""); 33 | } 34 | 35 | /** 36 | * 获取js解析后的数据 37 | * @param context 上下文 38 | * @param convertName js的处理方法 39 | * @param jsonString 单个上传字段 40 | * @return js解析处理后的数据 41 | */ 42 | public static String engineJs(J2V8Interface context,String convertName,String jsonString){ 43 | return engineJs(context,convertName,jsonString,null,"",null); 44 | } 45 | 46 | /** 47 | * 获取js解析后的数据 48 | * @param context 上下文 49 | * @param convertName js的处理方法 50 | * @param list 多个上传字段 51 | * @return js解析处理后的数据 52 | */ 53 | public static String engineJs(J2V8Interface context,String convertName,List list){ 54 | return engineJs(context,convertName,"",list,"",null); 55 | } 56 | 57 | /** 58 | * 获取js解析后的数据 59 | * @param context 上下文 60 | * @param convertName js的处理方法 61 | * @param jsonString 单个上传字段 62 | * @param list 多个上传字段 63 | * @param registName java回调注册的方法 64 | * @param voidCallback 注册java方法到js中的处理回调 65 | * @return js解析处理后的数据 66 | */ 67 | public static String engineJs(J2V8Interface context, String convertName, String jsonString, List list, String registName, JavaVoidCallback voidCallback){ 68 | if (null == context) return ""; 69 | if (TextUtils.isEmpty(convertName)) return ""; 70 | String jsonJs = ""; 71 | Log.d("j2v8Helper----->","js处理开始"); 72 | if (TextUtils.isEmpty(context.getJs())){ 73 | Log.d("j2v8Helper----->","js读取本地js文件中"); 74 | InputStream INPUTSTREAM = context.getClass().getResourceAsStream("/assets/j2v8/j2v8test.js");//获取js脚本的输入流 75 | try { 76 | jsonJs = J2V8Util.supplyAsync(INPUTSTREAM); 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } 80 | Log.d("j2v8Helper----->","本地js文件读取完成"); 81 | }else { 82 | Log.d("j2v8Helper----->","js读取数据库js脚本中"); 83 | jsonJs = context.getJs(); 84 | } 85 | V8 v8 = V8.createV8Runtime();//启动v8 86 | Log.d("j2v8Helper----->","v8已启动"); 87 | String response = "";//js解析结果 88 | if (!TextUtils.isEmpty(jsonJs)) { 89 | //先判断v8是否存在,以及是否被释放 90 | if (null != v8 && !v8.isReleased()) { 91 | //v8获取js的方法类 92 | v8.executeVoidScript(jsonJs); 93 | Log.d("j2v8Helper----->","js已注入到v8中"); 94 | if (null != voidCallback){ 95 | //如果回调不为空,则注册回调 96 | v8.registerJavaMethod(voidCallback,registName); 97 | Log.d("j2v8Helper----->" ,registName + "方法已注册到js"); 98 | } 99 | List putList = new ArrayList<>(); 100 | if (!TextUtils.isEmpty(jsonString)){ 101 | if (list == null){ 102 | list = new ArrayList<>(); 103 | } 104 | list.add(jsonString); 105 | Log.d("j2v8Helper----->","当前是单字段上传"); 106 | } 107 | if (null != list){ 108 | putList.addAll(list); 109 | Log.d("j2v8Helper----->","当前是多字段上传"); 110 | } 111 | response = J2V8Util.v8StringFunction(v8, convertName, J2V8Util.getV8Array(v8, putList)); 112 | Log.d("j2v8Helper----->","js处理完毕"); 113 | Log.d("j2v8Helper----->","js解析结果:"+response); 114 | v8.release();//使用完,释放v8 115 | Log.d("j2v8Helper----->","v8已释放"); 116 | } 117 | }else { 118 | Log.d("j2v8Helper----->","获取js失败"); 119 | } 120 | return response; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/J2V8Interface.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | /** 4 | * 描述: 5 | * 作者 : Tong 6 | * e-mail : itangbei@sina.com 7 | * 创建时间: 2019/8/28. 8 | */ 9 | public interface J2V8Interface { 10 | 11 | String getJs(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/J2V8InterfaceImpl.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * 描述: 7 | * 作者 : Tong 8 | * e-mail : itangbei@sina.com 9 | * 创建时间: 2019/8/28. 10 | */ 11 | @Deprecated 12 | public class J2V8InterfaceImpl implements J2V8Interface { 13 | 14 | public String jsString;//数据库中存入的js脚本函数 15 | 16 | 17 | 18 | public J2V8InterfaceImpl(){ 19 | 20 | } 21 | 22 | public J2V8InterfaceImpl(String jsString) { 23 | this.jsString = jsString; 24 | } 25 | 26 | @Override 27 | public String getJs() { 28 | return jsString; 29 | } 30 | 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/J2V8Single.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import com.eclipsesource.v8.JavaVoidCallback; 7 | import com.eclipsesource.v8.V8; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * 描述: j2v8的单例模式 目的是使用时js文件只读取一遍。 14 | * 作者 : Tong 15 | * e-mail : itangbei@sina.com 16 | * 创建时间: 2019/8/28. 17 | */ 18 | public class J2V8Single { 19 | 20 | private static J2V8Single instance = null; 21 | 22 | private J2V8Interface context; 23 | 24 | private String jsonJs = ""; 25 | 26 | /** 27 | * 初始化 28 | * @param context 29 | */ 30 | public J2V8Single(J2V8Interface context) { 31 | if (null == context) return; 32 | this.context = context; 33 | Log.d("J2V8Single----->","处理js脚本"); 34 | this.jsonJs = J2V8Util.getOssJsUrl("https://github.com/tangbei/j2v8_android/blob/master/j2v8test.js"); 35 | // this.jsonJs = J2V8Util.getLoaclJsUrl(context); 36 | if (!TextUtils.isEmpty(jsonJs)){ 37 | Log.d("J2V8Single----->","解析js脚本成功"); 38 | }else { 39 | Log.d("J2V8Single----->","解析js脚本失败"); 40 | } 41 | } 42 | 43 | public static J2V8Single getInstance(J2V8Interface context){ 44 | if (null == instance){ 45 | synchronized (J2V8Single.class){ 46 | if (null == instance){ 47 | return new J2V8Single(context); 48 | } 49 | } 50 | } 51 | return instance; 52 | } 53 | 54 | /** 55 | * 获取js解析后的数据 56 | * @param convertName js的处理方法 57 | * @return js解析处理后的数据 58 | */ 59 | public String engineJs(String convertName){ 60 | return engineJs(convertName,""); 61 | } 62 | 63 | /** 64 | * 获取js解析后的数据 65 | * @param convertName js的处理方法 66 | * @param jsonString 单个上传字段 67 | * @return js解析处理后的数据 68 | */ 69 | public String engineJs(String convertName,String jsonString){ 70 | return engineJs(convertName,jsonString,null,"",null); 71 | } 72 | 73 | /** 74 | * 获取js解析后的数据 75 | * @param convertName js的处理方法 76 | * @param list 多个上传字段 77 | * @return js解析处理后的数据 78 | */ 79 | public String engineJs(String convertName, List list){ 80 | return engineJs(convertName,"",list,"",null); 81 | } 82 | 83 | /** 84 | * 获取js解析后的数据 85 | * @param convertName js的处理方法 86 | * @param jsonString 单个上传字段 87 | * @param list 多个上传字段 88 | * @param registName java回调注册的方法 89 | * @param voidCallback 注册java方法到js中的处理回调 90 | * @return js解析处理后的数据 91 | */ 92 | public String engineJs(String convertName, String jsonString, List list, String registName, JavaVoidCallback voidCallback){ 93 | if (null == context) return ""; 94 | if (TextUtils.isEmpty(jsonJs)) return "js文件不存在"; 95 | if (TextUtils.isEmpty(convertName)) return "解析的方法名不能为空"; 96 | V8 v8 = V8.createV8Runtime();//启动v8、 97 | Log.d("J2V8Single----->","v8已启动"); 98 | String response = "";//js解析结果 99 | if (!TextUtils.isEmpty(jsonJs)) { 100 | //先判断v8是否存在,以及是否被释放 101 | if (null != v8 && !v8.isReleased()) { 102 | //v8获取js的方法类 103 | v8.executeVoidScript(jsonJs); 104 | Log.d("J2V8Single----->","js已注入到v8中"); 105 | if (null != voidCallback){ 106 | //如果回调不为空,则注册回调 107 | v8.registerJavaMethod(voidCallback,registName); 108 | Log.d("J2V8Single----->", registName + "方法已注册到js"); 109 | } 110 | List putList = new ArrayList<>(); 111 | if (!TextUtils.isEmpty(jsonString)){ 112 | if (list == null){ 113 | list = new ArrayList<>(); 114 | } 115 | list.add(jsonString); 116 | Log.d("J2V8Single----->","当前是单字段上传"); 117 | } 118 | if (null != list){ 119 | putList.addAll(list); 120 | Log.d("J2V8Single----->","当前是多字段上传"); 121 | } 122 | response = J2V8Util.v8StringFunction(v8, convertName, J2V8Util.getV8Array(v8, putList)); 123 | Log.d("J2V8Single----->","js处理完毕"); 124 | Log.d("J2V8Single----->","js解析结果:"+response); 125 | v8.release();//使用完,释放v8 126 | Log.d("J2V8Single----->","v8已释放"); 127 | } 128 | }else { 129 | Log.d("J2V8Single----->","获取js失败"); 130 | } 131 | return response; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/J2V8Util.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | import android.os.AsyncTask; 4 | import android.util.Log; 5 | 6 | import com.eclipsesource.v8.V8; 7 | import com.eclipsesource.v8.V8Array; 8 | import com.eclipsesource.v8.V8Function; 9 | import java.io.BufferedReader; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.InputStreamReader; 13 | import java.net.URL; 14 | import java.net.URLConnection; 15 | import java.util.List; 16 | import java.util.concurrent.CompletableFuture; 17 | 18 | /** 19 | * 描述: j2v8工具类 20 | * 作者 : Tong 21 | * e-mail : itangbei@sina.com 22 | * 创建时间: 2019/8/5. 23 | */ 24 | public class J2V8Util { 25 | 26 | /** 27 | * 获取oss上的js文件,并转换成String返回 28 | * 如果是获取网络地址,则使用 J2V8Single.class 处理 29 | * @param _url oss上的js地址:https://github.com/tangbei/j2v8_android/blob/master/j2v8test.js 30 | * @return 31 | */ 32 | public static String getOssJsUrl(String _url){ 33 | String jsPath =""; 34 | try { 35 | // 构造URL 36 | URL url = new URL(_url); 37 | // 打开连接 38 | URLConnection con = url.openConnection(); 39 | // 设置请求超时为5s 40 | con.setConnectTimeout(5 * 1000); 41 | // 输入流 42 | InputStream is = con.getInputStream(); 43 | jsPath = supplyAsync(is); 44 | is.close(); 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | } 48 | return jsPath; 49 | } 50 | 51 | /** 52 | * 获取本地js文件,并转换成string 53 | * @param context 54 | * @return 55 | */ 56 | public static String getLocalJsUrl(J2V8Interface context) { 57 | String localString = ""; 58 | final InputStream INPUTSTREAM = context.getClass().getClassLoader().getResourceAsStream("j2v8/j2v8test.js");//获取js脚本的输入流 59 | try { 60 | localString = supplyAsync(INPUTSTREAM);//获取js处理后的字符串 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | Log.d("J2V8Single----->","js处理失败"); 64 | } 65 | return localString; 66 | } 67 | 68 | /** 69 | * 异步处理js文件 70 | * 71 | * @param inputStream 72 | * @return 73 | * @throws Exception 74 | */ 75 | public static String supplyAsync(final InputStream inputStream) { 76 | return getFileContent(inputStream); 77 | } 78 | 79 | /** 80 | * 读取js并转换成string字符串 81 | * 82 | * @param inputStream 83 | * @return 84 | */ 85 | public static String getFileContent(InputStream inputStream) { 86 | //将json数据变成字符串 87 | StringBuilder stringBuilder = new StringBuilder(); 88 | try { 89 | BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream)); 90 | //通过管理器打开文件并读取 91 | String line; 92 | while ((line = bf.readLine()) != null) { 93 | stringBuilder.append(line).append("\r\n");//为了保证js的严格“行”属性,这里主动追加\r\n 94 | } 95 | bf.close(); 96 | } 97 | catch (IOException e) { 98 | e.printStackTrace(); 99 | } 100 | return stringBuilder.toString(); 101 | } 102 | 103 | /** 104 | * 拼接上传参数-获取v8array 105 | * 106 | * @param v8 107 | * @param list 108 | * @return 109 | */ 110 | public static V8Array getV8Array(V8 v8, List list) { 111 | V8Array array = null; 112 | if (null == list) return null; 113 | if (null != v8 && !v8.isReleased()) { 114 | array = new V8Array(v8); 115 | for (Object item : list) { 116 | if (item instanceof String){ 117 | array.push((String) item); 118 | } else if (item instanceof Integer) { 119 | array.push((Integer) item); 120 | }else if (item instanceof Boolean){ 121 | array.push((Boolean) item); 122 | } 123 | } 124 | } 125 | return array; 126 | } 127 | 128 | /** 129 | * 获取js方法中返回string类型的数据 130 | * 131 | * @param v8 132 | * @param name js函数名 133 | * @param array 上传参数 134 | * @return 返回字符串 135 | */ 136 | public static String v8StringFunction(V8 v8, String name, V8Array array) { 137 | String result = ""; 138 | try { 139 | if (v8 != null && !v8.isReleased()) { 140 | if (null != array) { 141 | result = v8.executeStringFunction(name, array); 142 | array.release(); 143 | } else { 144 | result = v8.executeStringFunction(name, null); 145 | } 146 | } 147 | } catch (Exception e) { 148 | e.printStackTrace(); 149 | } 150 | return result; 151 | } 152 | 153 | /** 154 | * 获取js方法中返回boolean类型的数据 155 | * 156 | * @param v8 157 | * @param name js函数名 158 | * @param array 上传参数 159 | * @return 返回值 160 | */ 161 | public static Boolean v8BooleanFunction(V8 v8, String name, V8Array array) { 162 | boolean result = false; 163 | try { 164 | if (v8 != null && !v8.isReleased()) { 165 | if (null != array) { 166 | result = v8.executeBooleanFunction(name, array); 167 | array.release(); 168 | } else { 169 | result = v8.executeBooleanFunction(name, null); 170 | } 171 | } 172 | } catch (Exception e) { 173 | e.printStackTrace(); 174 | } 175 | return result; 176 | } 177 | 178 | /** 179 | * 获取js方法中返回Int类型的数据 180 | * 181 | * @param v8 182 | * @param name js函数名 183 | * @param array 上传参数 184 | * @return 返回值 185 | */ 186 | public static Integer v8IntFunction(V8 v8, String name, V8Array array) { 187 | int result = 0; 188 | try { 189 | if (v8 != null && !v8.isReleased()) { 190 | if (null != array) { 191 | result = v8.executeIntegerFunction(name, array); 192 | array.release(); 193 | } else { 194 | result = v8.executeIntegerFunction(name, null); 195 | } 196 | } 197 | } catch (Exception e) { 198 | e.printStackTrace(); 199 | } 200 | return result; 201 | } 202 | 203 | /** 204 | * 获取js函数 205 | * 206 | * @param v8 207 | * @param name 函数名 208 | * @param array 上传参数 209 | */ 210 | public static void v8Void(V8 v8, String name, V8Array array, V8Function javaCallback) { 211 | try { 212 | if (v8 != null && !v8.isReleased()) { 213 | if (null != array) { 214 | array.push(javaCallback); 215 | v8.executeVoidFunction(name, array); 216 | array.release(); 217 | } else { 218 | v8.executeVoidFunction(name, null); 219 | } 220 | } 221 | } catch (Exception e) { 222 | e.printStackTrace(); 223 | } 224 | return; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/J2V8ValueCallBack.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | /** 4 | * 描述: 5 | * 作者 : Tong 6 | * e-mail : itangbei@sina.com 7 | * 创建时间: 2019/9/18. 8 | */ 9 | public interface J2V8ValueCallBack { 10 | 11 | void getReadValue(String value); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/J2v8Example.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | import android.app.Activity; 4 | import com.eclipsesource.v8.V8; 5 | import com.eclipsesource.v8.V8Function; 6 | import com.tang.test.AsyncTaskBackListener; 7 | import com.tang.test.J2V8ReadJavaScript; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * 描述: 14 | * 作者 : Tong 15 | * e-mail : itangbei@sina.com 16 | * 创建时间: 2019/9/18. 17 | */ 18 | public class J2v8Example { 19 | 20 | public static void getJs(Activity activity,final JavaCallbackImpl javaCallback, final JavaVoidCallbackImpl callbackImpl, final J2V8ValueCallBack valueCallBack){ 21 | final V8 v8 = V8.createV8Runtime(); 22 | J2V8ReadJavaScript readJavaScript = new J2V8ReadJavaScript(activity, new AsyncTaskBackListener() 23 | { 24 | @Override 25 | public void onAsyncTaskCallBack(String s) 26 | { 27 | 28 | if (v8 != null && !v8.isReleased()) 29 | { 30 | StringBuffer stringBuffer = new StringBuffer(); 31 | v8.executeVoidScript(s);//拿到当前js的方法 32 | 33 | //在js脚本中注册java方法 34 | v8.registerJavaMethod(callbackImpl,"javaVoid"); 35 | 36 | v8.registerJavaMethod(javaCallback,"javaBack"); 37 | 38 | List list1 = new ArrayList<>(); 39 | list1.add("我是js脚本中:j2v8String方法的第一个参数哦"); 40 | list1.add("我是js脚本中:j2v8String方法的第二个参数哦"); 41 | stringBuffer.append(J2V8Util.v8StringFunction(v8,"j2v8String",J2V8Util.getV8Array(v8,list1)) + "/n"); 42 | 43 | List list2 = new ArrayList<>(); 44 | list2.add(10000); 45 | list2.add(20000); 46 | stringBuffer.append(",------->我是调用的Int返回方法:" + J2V8Util.v8IntFunction(v8,"j2v8Int",J2V8Util.getV8Array(v8,list2))); 47 | 48 | List list3 = new ArrayList<>(); 49 | list3.add("aaa"); 50 | list3.add("aaa"); 51 | stringBuffer.append(",------->我是调用的boolean返回方法:"+ J2V8Util.v8BooleanFunction(v8,"j2v8Boolean",J2V8Util.getV8Array(v8,list3))); 52 | 53 | //判断是否是函数 54 | if (v8.getType("putVoid") == V8.V8_FUNCTION) { 55 | List list4 = new ArrayList<>(); 56 | list4.add(234); 57 | list4.add(33); 58 | V8Function call = (V8Function) v8.getObject("putVoid"); 59 | int ss = (int) call.call(null, J2V8Util.getV8Array(v8, list4)); 60 | call.close(); 61 | stringBuffer.append(",------->调用js的方法并返回结果:" + ss); 62 | } 63 | 64 | List list5 = new ArrayList<>(); 65 | list5.add("我是java注册的回调函数:参数1"); 66 | list5.add("我是java注册的回到函数:参数2"); 67 | stringBuffer.append(J2V8Util.v8StringFunction(v8,"javaCallBack",J2V8Util.getV8Array(v8,list5))); 68 | 69 | valueCallBack.getReadValue(stringBuffer.toString()); 70 | v8.release(false); 71 | } 72 | } 73 | }); 74 | 75 | readJavaScript.execute(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/JavaCallbackImpl.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | import com.eclipsesource.v8.JavaCallback; 4 | import com.eclipsesource.v8.V8Array; 5 | import com.eclipsesource.v8.V8Object; 6 | 7 | /** 8 | * 描述: js调用java方法 并返回结果 9 | * 作者 : Tong 10 | * e-mail : itangbei@sina.com 11 | * 创建时间: 2019/9/18. 12 | */ 13 | public class JavaCallbackImpl implements JavaCallback { 14 | @Override 15 | public Object invoke(V8Object v8Object, V8Array v8Array) { 16 | 17 | String callback = ""; 18 | if (null != v8Array.get(0)){ 19 | callback = (String) v8Array.get(0); 20 | 21 | callback = "我是java回调结果,并再次处理返回:" + callback; 22 | } 23 | return callback; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/tang/test/j2v8/JavaVoidCallbackImpl.java: -------------------------------------------------------------------------------- 1 | package com.tang.test.j2v8; 2 | 3 | import android.util.Log; 4 | 5 | import com.eclipsesource.v8.JavaVoidCallback; 6 | import com.eclipsesource.v8.V8Array; 7 | import com.eclipsesource.v8.V8Object; 8 | 9 | /** 10 | * 描述: js调用java方法返回 11 | * 作者 : Tong 12 | * e-mail : itangbei@sina.com 13 | * 创建时间: 2019/9/18. 14 | */ 15 | public class JavaVoidCallbackImpl implements JavaVoidCallback { 16 | 17 | @Override 18 | public void invoke(V8Object v8Object, V8Array v8Array) { 19 | 20 | if (null != v8Array.get(0)){ 21 | String tt = v8Object.getString("name"); 22 | String str = (String) v8Array.get(0); 23 | 24 | Log.d("java方法返回结果----------->",tt + str); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |