├── app
├── .gitignore
├── libs
│ ├── x86
│ │ └── liblbs.so
│ ├── armeabi
│ │ └── liblbs.so
│ └── tbs_sdk_thirdapp_v3.6.0.1310_43612_sharewithdownload_withoutGame_obfs_20180706_163319.jar
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.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
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_file_display.xml
│ │ │ │ ├── activity_web_browser.xml
│ │ │ │ └── activity_main.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── github
│ │ │ │ └── benjamin
│ │ │ │ └── tbsreader
│ │ │ │ ├── bridge
│ │ │ │ ├── CallBackFunction.java
│ │ │ │ ├── BridgeHandler.java
│ │ │ │ ├── WebViewJavascriptBridge.java
│ │ │ │ ├── DefaultHandler.java
│ │ │ │ ├── BridgeConfig.java
│ │ │ │ ├── BridgeWebViewClientListener.java
│ │ │ │ ├── OnWebChromeClientListener.java
│ │ │ │ ├── SimpleBridgeWebViewClientListener.java
│ │ │ │ ├── Message.java
│ │ │ │ ├── WebChromeClientListener.java
│ │ │ │ ├── BridgeUtil.java
│ │ │ │ ├── BridgeWebViewClient.java
│ │ │ │ └── TbsBridgeWebView.java
│ │ │ │ ├── utils
│ │ │ │ ├── WebViewJavaScriptFunction.java
│ │ │ │ └── X5WebView.java
│ │ │ │ ├── okgo
│ │ │ │ └── Ok.java
│ │ │ │ ├── MyAppliction.java
│ │ │ │ ├── FileDisplayActivity.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── WebBrowserActivity.java
│ │ ├── AndroidManifest.xml
│ │ └── assets
│ │ │ └── WebViewJavascriptBridge.js
│ ├── test
│ │ └── java
│ │ │ └── github
│ │ │ └── benjamin
│ │ │ └── tbsreader
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── github
│ │ └── benjamin
│ │ └── tbsreader
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── Bridge.rar
├── img
└── gif.gif
├── .idea
├── caches
│ ├── gradle_models.ser
│ └── build_file_checksums.ser
├── vcs.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
└── codeStyles
│ └── Project.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/Bridge.rar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/Bridge.rar
--------------------------------------------------------------------------------
/img/gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/img/gif.gif
--------------------------------------------------------------------------------
/app/libs/x86/liblbs.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/libs/x86/liblbs.so
--------------------------------------------------------------------------------
/app/libs/armeabi/liblbs.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/libs/armeabi/liblbs.so
--------------------------------------------------------------------------------
/.idea/caches/gradle_models.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/.idea/caches/gradle_models.ser
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TBSreader
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/CallBackFunction.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | public interface CallBackFunction {
4 |
5 | void onCallBack(String data);
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/BridgeHandler.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | public interface BridgeHandler {
4 |
5 | void handler(String data, CallBackFunction function);
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/app/libs/tbs_sdk_thirdapp_v3.6.0.1310_43612_sharewithdownload_withoutGame_obfs_20180706_163319.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabinDev/TBSreader/HEAD/app/libs/tbs_sdk_thirdapp_v3.6.0.1310_43612_sharewithdownload_withoutGame_obfs_20180706_163319.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Sep 21 09:40:40 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/WebViewJavascriptBridge.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 |
4 | public interface WebViewJavascriptBridge {
5 |
6 | void send(String data);
7 |
8 | void send(String data, CallBackFunction responseCallback);
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #FFFFFF
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/DefaultHandler.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | public class DefaultHandler implements BridgeHandler {
4 |
5 | String TAG = "DefaultHandler";
6 |
7 | @Override
8 | public void handler(String data, CallBackFunction function) {
9 | if (function != null) {
10 | function.onCallBack("DefaultHandler response data");
11 | }
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/BridgeConfig.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | /**
4 | * 配置文件
5 | */
6 | public class BridgeConfig {
7 |
8 | public static final String toLoadJs = "WebViewJavascriptBridge.js";
9 | /**
10 | * 默认桥名
11 | */
12 | public static final String defaultJs = "WebViewJavascriptBridge";
13 | /**
14 | * 自定义桥名
15 | */
16 | public static String customJs = BridgeConfig.defaultJs;
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/utils/WebViewJavaScriptFunction.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.utils;
2 | /**
3 | * Project : TBSreader.
4 | * Package name: github.benjamin.tbsreader.utils
5 | * Created by : Benjamin.
6 | * Created time: 2018/1/3 10:33
7 | * Changed by : Benjamin.
8 | * Changed time: 2018/1/3 10:33
9 | * Class description: WebViewJavaScriptFunction
10 | */
11 |
12 | public interface WebViewJavaScriptFunction {
13 |
14 | void onJsFunctionCalled(String tag);
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/test/java/github/benjamin/tbsreader/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_file_display.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/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/main/res/layout/activity_web_browser.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
17 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/github/benjamin/tbsreader/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader;
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() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("github.benjamin.tbsreader", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "github.benjamin.tbsreader"
7 | minSdkVersion 15
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | //配置so文件
13 | ndk {
14 | abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
15 | }
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | sourceSets {
24 | main {
25 | jniLibs.srcDirs = ['libs']
26 | }
27 | }
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 | }
33 |
34 | dependencies {
35 | implementation fileTree(include: ['*.jar'], dir: 'libs')
36 | implementation 'com.android.support:appcompat-v7:27.1.1'
37 | //必须使用
38 | implementation 'com.lzy.net:okgo:3.0.4'
39 | implementation files('libs/tbs_sdk_thirdapp_v3.6.0.1310_43612_sharewithdownload_withoutGame_obfs_20180706_163319.jar')
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/okgo/Ok.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.okgo;
2 |
3 | import com.lzy.okgo.OkGo;
4 | import com.lzy.okgo.callback.FileCallback;
5 | import com.lzy.okgo.model.Progress;
6 | import com.lzy.okgo.model.Response;
7 |
8 | import java.io.File;
9 |
10 | /**
11 | * Project : TBSreader.
12 | * Package name: github.benjamin.tbsreader.okgo
13 | * Created by : Benjamin.
14 | * Created time: 2018/1/8 12:46
15 | * Changed by : Benjamin.
16 | * Changed time: 2018/1/8 12:46
17 | * Class description:
18 | */
19 |
20 | public class Ok {
21 | private static Ok okClicent;
22 |
23 | private Ok() {
24 |
25 | }
26 |
27 | public static Ok getInstant() {
28 | if (okClicent == null) {
29 | okClicent = new Ok();
30 | }
31 | return okClicent;
32 | }
33 |
34 | public void loadFile(String url, String tag) {
35 | OkGo.get("").execute(new FileCallback() {
36 | @Override
37 | public void onSuccess(Response response) {
38 |
39 | }
40 |
41 | @Override
42 | public void onError(Response response) {
43 | super.onError(response);
44 | }
45 |
46 | @Override
47 | public void downloadProgress(Progress progress) {
48 | super.downloadProgress(progress);
49 |
50 | }
51 | });
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/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/java/github/benjamin/tbsreader/MyAppliction.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import com.lzy.okgo.OkGo;
7 | import com.lzy.okgo.interceptor.HttpLoggingInterceptor;
8 | import com.tencent.smtt.sdk.QbSdk;
9 |
10 | import java.util.concurrent.TimeUnit;
11 | import java.util.logging.Level;
12 |
13 | import okhttp3.OkHttpClient;
14 |
15 | /**
16 | * Project : TBSreader.
17 | * Package name: github.benjamin.tbsreader
18 | * Created by : Benjamin.
19 | * Created time: 2018/1/3 10:33
20 | * Changed by : Benjamin.
21 | * Changed time: 2018/1/3 10:33
22 | * Class description: MyAppliction
23 | */
24 |
25 | public class MyAppliction extends Application {
26 |
27 |
28 | @Override
29 | public void onCreate() {
30 | super.onCreate();
31 | initOkGo();
32 | //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
33 | QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
34 | @Override
35 | public void onViewInitFinished(boolean arg0) {
36 | // TODO Auto-generated method stub
37 | //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
38 | Log.e("app", " =========onViewInitFinished is " + arg0);
39 | }
40 |
41 | @Override
42 | public void onCoreInitFinished() {
43 | // TODO Auto-generated method stub
44 | }
45 | };
46 | //x5内核初始化接口
47 | QbSdk.initX5Environment(getApplicationContext(), cb);
48 | }
49 |
50 | private void initOkGo() {
51 | OkGo.getInstance().init(this);
52 | OkHttpClient.Builder builder = new OkHttpClient.Builder();
53 | HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor("OkGo");
54 | //log打印级别,决定了log显示的详细程度
55 | loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);
56 | //log颜色级别,决定了log在控制台显示的颜色
57 | loggingInterceptor.setColorLevel(Level.INFO);
58 | builder.addInterceptor(loggingInterceptor);
59 | //全局的读取超时时间
60 | builder.readTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
61 | //全局的写入超时时间
62 | builder.writeTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
63 | //全局的连接超时时间
64 | builder.connectTimeout(OkGo.DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
18 |
27 |
28 |
37 |
38 |
47 |
48 |
57 |
58 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **https://x5.tencent.com/tbs/ 腾讯浏览服务**
2 | ## 操作演示
3 | 
4 | ## 1.腾讯浏览器集成
5 |
6 | X5内核相对于系统webview,具有下述明显优势:
7 |
8 | 1) 速度快:相比系统webview的网页打开速度有30+%的提升;
9 |
10 | 2) 省流量:使用云端优化技术使流量节省20+%;
11 |
12 | 3) 更安全:安全问题可以在24小时内修复;
13 |
14 | 4) 更稳定:经过亿级用户的使用考验,CRASH率低于0.15%;
15 |
16 | 5) 兼容好:无系统内核的碎片化问题,更少的兼容性问题;
17 |
18 | 6) 体验优:支持夜间模式、适屏排版、字体设置等浏览增强功能;
19 |
20 | 7) 功能全:在Html5、ES6上有更完整支持;
21 |
22 | 8) 更强大:集成强大的视频播放器,支持视频格式远多于系统webview;
23 |
24 | 9) 视频和文件格式的支持x5内核多于系统内核
25 |
26 | 10) 防劫持是x5内核的一大亮点
27 | ## 2.tbs文件查看能力
28 |
29 | 目前支持42种文件格式,包括20种文档、12种音乐、6种图片和4种压缩包。帮助应用实现应用内文档浏览,无需跳转调用其他应用。
30 |
31 | ## 3.jsbridge支持解决Android和H5之间的通讯问题
32 |
33 | android调用JS方法
34 |
35 | ```java
36 | String message = "javascript:phoneCallJs(\"" + "你好 大胡子" + "\")";
37 | //需要放到pagefind里面或者在loadurl后面否则会返回null
38 | webView.loadUrl(message);
39 | ```
40 | ```javascript
41 | function phoneCallJs(str) {
42 | alert(str.toString());
43 |
44 | }
45 | ```
46 | JS调用Android方法
47 |
48 |
49 |
50 | ```java
51 | webView.registerHandler("jsCallPhone", new BridgeHandler() {
52 | @Override
53 | public void handler(String data, CallBackFunction function) {
54 | Log.i(TAG, "回传结果:" + data);
55 | Toast.makeText(WebBrowserActivity.this, data, Toast.LENGTH_SHORT).show();
56 | }
57 | });
58 | ```
59 |
60 |
61 |
62 |
63 |
64 |
65 | ### 使用方式:
66 | #### 下载关联moudle
67 | #### *支持查看网络文件(注意打开权限)
68 |
69 |
70 |
71 |
72 | #### 打开文件(word/excell/pdf/以及其他很多办公文档格式)
73 | FileDisplayActivity.openActivity(this, "http://www.dabinDev.cn/file/123pdf.pdf");
74 |
75 |
76 | #### 打开文件 视频
77 | Bundle extraData = new Bundle();
78 | extraData.putInt("screenMode", 102);
79 | extraData.putBoolean("supportLiteWnd", false);
80 | TbsVideo.openVideo(this, "http://www.dabinDev.cn/file/12312312.mp4", extraData);
81 |
82 | 前端页面放在压缩目录 `bridge`里面
83 | #### 其他解决方式
84 | 1.永中云
85 | [http://www.dcsapi.com/](http://www.dcsapi.com/ "http://www.dcsapi.com/")
86 | - 这个用起来也很方便,不需要做什么操作,注册永中云账号,在管理后台吧你们服务器的域名添加信任,然后在你移动端本地用X5浏览器(用本地浏览器需要设置的东西就比较多了,js插件什么的,推荐使用X5浏览器),打开永中云给你拼接后的url就可以直接查看。
87 | - 注*每天每个服务器域名对应文件,免费用户解析只有500次,如果次数超过当天就无法使用,所以自己做做测试什么的还可以
88 | - 将你服务器的文件转成pdf 在浏览器查看,集成简单但是次数显示,支持的格式没有腾讯的多
89 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/BridgeWebViewClientListener.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Bundle;
5 | import android.view.KeyEvent;
6 |
7 | import com.tencent.smtt.export.external.interfaces.ClientCertRequest;
8 | import com.tencent.smtt.export.external.interfaces.HttpAuthHandler;
9 | import com.tencent.smtt.export.external.interfaces.SslError;
10 | import com.tencent.smtt.export.external.interfaces.SslErrorHandler;
11 | import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
12 | import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
13 | import com.tencent.smtt.sdk.WebView;
14 |
15 | public interface BridgeWebViewClientListener {
16 |
17 | /**
18 | * @param view webview
19 | * @param url url
20 | * @return boolean
21 | * 非js桥的超链接回调回去自行处理
22 | */
23 | boolean shouldOverrideUrlLoading(WebView view, String url);
24 |
25 | void onPageStarted(WebView view, String url, Bitmap favicon);
26 |
27 | void onPageFinished(WebView view, String url);
28 |
29 | void onReceivedError(WebView view, int errorCode, String description, String failingUrl);
30 |
31 | void onLoadResource(WebView webView, String s);
32 |
33 | void onReceivedHttpError(WebView webView, WebResourceRequest webResourceRequest, WebResourceResponse webResourceResponse);
34 |
35 | WebResourceResponse shouldInterceptRequest(WebView webView, String s);
36 |
37 | WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest);
38 |
39 | WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest, Bundle bundle);
40 |
41 | void doUpdateVisitedHistory(WebView webView, String s, boolean b);
42 |
43 | boolean onFormResubmission(WebView webView, android.os.Message message, android.os.Message message1);
44 |
45 | boolean onReceivedHttpAuthRequest(WebView webView, HttpAuthHandler httpAuthHandler, String s, String s1);
46 |
47 | boolean onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError);
48 |
49 | boolean onReceivedClientCertRequest(WebView webView, ClientCertRequest clientCertRequest);
50 |
51 | void onScaleChanged(WebView webView, float v, float v1);
52 |
53 | void onUnhandledKeyEvent(WebView webView, KeyEvent keyEvent);
54 |
55 | boolean shouldOverrideKeyEvent(WebView webView, KeyEvent keyEvent);
56 |
57 | void onTooManyRedirects(WebView webView, android.os.Message message, android.os.Message message1);
58 |
59 | void onReceivedLoginRequest(WebView webView, String s, String s1, String s2);
60 |
61 | void onDetectedBlankScreen(String s, int i);
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/OnWebChromeClientListener.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import android.graphics.Bitmap;
4 | import android.net.Uri;
5 | import android.view.View;
6 |
7 | import com.tencent.smtt.export.external.interfaces.ConsoleMessage;
8 | import com.tencent.smtt.export.external.interfaces.GeolocationPermissionsCallback;
9 | import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
10 | import com.tencent.smtt.export.external.interfaces.JsPromptResult;
11 | import com.tencent.smtt.export.external.interfaces.JsResult;
12 | import com.tencent.smtt.sdk.ValueCallback;
13 | import com.tencent.smtt.sdk.WebChromeClient;
14 | import com.tencent.smtt.sdk.WebStorage;
15 | import com.tencent.smtt.sdk.WebView;
16 |
17 | public interface OnWebChromeClientListener {
18 |
19 | void onReceivedTitle(WebView view, String title);
20 |
21 | void onProgressChanged(WebView view, int newProgress);
22 |
23 | void onExceededDatabaseQuota(String url, String databaseIdentifier, long quota, long estimatedDatabaseSize, long totalQuota, WebStorage.QuotaUpdater quotaUpdater);
24 |
25 | Bitmap getDefaultVideoPoster();
26 |
27 | void getVisitedHistory(ValueCallback valueCallback);
28 |
29 | boolean onConsoleMessage(ConsoleMessage consoleMessage);
30 |
31 | boolean onCreateWindow(WebView webView, boolean isDialog, boolean isUserGesture, android.os.Message message);
32 |
33 | void onGeolocationPermissionsHidePrompt();
34 |
35 | void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissionsCallback geolocationPermissionsCallback);
36 |
37 | void onHideCustomView();
38 |
39 | boolean onJsAlert(WebView view, String url, String message, JsResult result);
40 |
41 | boolean onJsConfirm(WebView view, String url, String message, JsResult result);
42 |
43 | boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result);
44 |
45 | boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result);
46 |
47 | boolean onJsTimeout();
48 |
49 | void onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater);
50 |
51 | void onReceivedIcon(WebView webView, Bitmap bitmap);
52 |
53 | void onReceivedTouchIconUrl(WebView webView, String url, boolean precomposed);
54 |
55 | void onRequestFocus(WebView webView);
56 |
57 | void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback);
58 |
59 | void onShowCustomView(View view, int requestedOrientation, IX5WebChromeClient.CustomViewCallback customViewCallback);
60 |
61 | void onCloseWindow(WebView webView);
62 |
63 | View getVideoLoadingProgressView();
64 |
65 | void openFileChooser(ValueCallback valueCallback, String s, String s1);
66 |
67 | boolean onShowFileChooser(WebView webView, ValueCallback valueCallback, WebChromeClient.FileChooserParams fileChooserParams);
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/utils/X5WebView.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.utils;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.widget.TextView;
9 |
10 | import com.tencent.smtt.sdk.WebSettings;
11 | import com.tencent.smtt.sdk.WebSettings.LayoutAlgorithm;
12 | import com.tencent.smtt.sdk.WebView;
13 | import com.tencent.smtt.sdk.WebViewClient;
14 |
15 | public class X5WebView extends WebView {
16 | TextView title;
17 | private WebViewClient client = new WebViewClient() {
18 | /**
19 | * 防止加载网页时调起系统浏览器
20 | */
21 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
22 | view.loadUrl(url);
23 | return true;
24 | }
25 | };
26 |
27 | @SuppressLint("SetJavaScriptEnabled")
28 | public X5WebView(Context arg0, AttributeSet arg1) {
29 | super(arg0, arg1);
30 | this.setWebViewClient(client);
31 | // this.setWebChromeClient(chromeClient);
32 | // WebStorage webStorage = WebStorage.getInstance();
33 | initWebViewSettings();
34 | this.getView().setClickable(true);
35 | }
36 |
37 | @SuppressLint("SetJavaScriptEnabled")
38 | private void initWebViewSettings() {
39 | WebSettings webSetting = this.getSettings();
40 | webSetting.setJavaScriptEnabled(true);
41 | webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
42 | webSetting.setAllowFileAccess(true);
43 | webSetting.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
44 | webSetting.setSupportZoom(true);
45 | webSetting.setBuiltInZoomControls(true);
46 | webSetting.setUseWideViewPort(true);
47 | webSetting.setSupportMultipleWindows(true);
48 | // webSetting.setLoadWithOverviewMode(true);
49 | webSetting.setAppCacheEnabled(true);
50 | // webSetting.setDatabaseEnabled(true);
51 | webSetting.setDomStorageEnabled(true);
52 | webSetting.setGeolocationEnabled(true);
53 | webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
54 | // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
55 | webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
56 | // webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
57 | webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);
58 |
59 |
60 | // this.getSettingsExtension().setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);//extension
61 | // settings 的设计
62 | }
63 |
64 | @Override
65 | protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
66 | boolean ret = super.drawChild(canvas, child, drawingTime);
67 | //画一个浏览器标识
68 | /*canvas.save();
69 | Paint paint = new Paint();
70 | paint.setColor(0x7fff0000);
71 | paint.setTextSize(24.f);
72 | paint.setAntiAlias(true);
73 | if (getX5WebViewExtension() != null) {
74 | canvas.drawText(this.getContext().getPackageName() + "-pid:"
75 | + android.os.Process.myPid(), 10, 50, paint);
76 | canvas.drawText(
77 | "X5 Core:" + QbSdk.getTbsVersion(this.getContext()), 10,
78 | 100, paint);
79 | } else {
80 | canvas.drawText(this.getContext().getPackageName() + "-pid:"
81 | + android.os.Process.myPid(), 10, 50, paint);
82 | canvas.drawText("Sys Core", 10, 100, paint);
83 | }
84 | canvas.drawText(Build.MANUFACTURER, 10, 150, paint);
85 | canvas.drawText(Build.MODEL, 10, 200, paint);
86 | canvas.restore();*/
87 | return ret;
88 | }
89 |
90 | public X5WebView(Context arg0) {
91 | super(arg0);
92 | setBackgroundColor(85621);
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/SimpleBridgeWebViewClientListener.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Bundle;
5 | import android.os.Message;
6 | import android.view.KeyEvent;
7 |
8 | import com.tencent.smtt.export.external.interfaces.ClientCertRequest;
9 | import com.tencent.smtt.export.external.interfaces.HttpAuthHandler;
10 | import com.tencent.smtt.export.external.interfaces.SslError;
11 | import com.tencent.smtt.export.external.interfaces.SslErrorHandler;
12 | import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
13 | import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
14 | import com.tencent.smtt.sdk.WebView;
15 |
16 | /**
17 | * description:
18 | */
19 |
20 | public class SimpleBridgeWebViewClientListener implements BridgeWebViewClientListener {
21 |
22 | @Override
23 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
24 | return false;
25 | }
26 |
27 | @Override
28 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
29 | }
30 |
31 | @Override
32 | public void onPageFinished(WebView view, String url) {
33 |
34 | }
35 |
36 | @Override
37 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
38 |
39 | }
40 |
41 | @Override
42 | public void onLoadResource(WebView webView, String s) {
43 |
44 | }
45 |
46 | @Override
47 | public void onReceivedHttpError(WebView webView, WebResourceRequest webResourceRequest, WebResourceResponse webResourceResponse) {
48 |
49 | }
50 |
51 | @Override
52 | public WebResourceResponse shouldInterceptRequest(WebView webView, String s) {
53 | return null;
54 | }
55 |
56 | @Override
57 | public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest) {
58 | return null;
59 | }
60 |
61 | @Override
62 | public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest, Bundle bundle) {
63 | return null;
64 | }
65 |
66 | @Override
67 | public void doUpdateVisitedHistory(WebView webView, String s, boolean b) {
68 |
69 | }
70 |
71 | @Override
72 | public boolean onFormResubmission(WebView webView, Message message, Message message1) {
73 | return false;
74 | }
75 |
76 | @Override
77 | public boolean onReceivedHttpAuthRequest(WebView webView, HttpAuthHandler httpAuthHandler, String s, String s1) {
78 | return false;
79 | }
80 |
81 | @Override
82 | public boolean onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
83 | return false;
84 | }
85 |
86 | @Override
87 | public boolean onReceivedClientCertRequest(WebView webView, ClientCertRequest clientCertRequest) {
88 | return false;
89 | }
90 |
91 | @Override
92 | public void onScaleChanged(WebView webView, float v, float v1) {
93 |
94 | }
95 |
96 | @Override
97 | public void onUnhandledKeyEvent(WebView webView, KeyEvent keyEvent) {
98 |
99 | }
100 |
101 | @Override
102 | public boolean shouldOverrideKeyEvent(WebView webView, KeyEvent keyEvent) {
103 | return false;
104 | }
105 |
106 | @Override
107 | public void onTooManyRedirects(WebView webView, Message message, Message message1) {
108 |
109 | }
110 |
111 | @Override
112 | public void onReceivedLoginRequest(WebView webView, String s, String s1, String s2) {
113 |
114 | }
115 |
116 | @Override
117 | public void onDetectedBlankScreen(String s, int i) {
118 |
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/Message.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * data of bridge
12 | *
13 | */
14 | public class Message {
15 |
16 | private String callbackId; //callbackId
17 | private String responseId; //responseId
18 | private String responseData; //responseData
19 | private String data; //data of message
20 | private String handlerName; //name of handler
21 |
22 | private final static String CALLBACK_ID_STR = "callbackId";
23 | private final static String RESPONSE_ID_STR = "responseId";
24 | private final static String RESPONSE_DATA_STR = "responseData";
25 | private final static String DATA_STR = "data";
26 | private final static String HANDLER_NAME_STR = "handlerName";
27 |
28 | public String getResponseId() {
29 | return responseId;
30 | }
31 | public void setResponseId(String responseId) {
32 | this.responseId = responseId;
33 | }
34 | public String getResponseData() {
35 | return responseData;
36 | }
37 | public void setResponseData(String responseData) {
38 | this.responseData = responseData;
39 | }
40 | public String getCallbackId() {
41 | return callbackId;
42 | }
43 | public void setCallbackId(String callbackId) {
44 | this.callbackId = callbackId;
45 | }
46 | public String getData() {
47 | return data;
48 | }
49 | public void setData(String data) {
50 | this.data = data;
51 | }
52 | public String getHandlerName() {
53 | return handlerName;
54 | }
55 | public void setHandlerName(String handlerName) {
56 | this.handlerName = handlerName;
57 | }
58 |
59 | public String toJson() {
60 | JSONObject jsonObject= new JSONObject();
61 | try {
62 | jsonObject.put(CALLBACK_ID_STR, getCallbackId());
63 | jsonObject.put(DATA_STR, getData());
64 | jsonObject.put(HANDLER_NAME_STR, getHandlerName());
65 | jsonObject.put(RESPONSE_DATA_STR, getResponseData());
66 | jsonObject.put(RESPONSE_ID_STR, getResponseId());
67 | return jsonObject.toString();
68 | } catch (JSONException e) {
69 | e.printStackTrace();
70 | }
71 | return null;
72 | }
73 |
74 | public static Message toObject(String jsonStr) {
75 | Message m = new Message();
76 | try {
77 | JSONObject jsonObject = new JSONObject(jsonStr);
78 | m.setHandlerName(jsonObject.has(HANDLER_NAME_STR) ? jsonObject.getString(HANDLER_NAME_STR):null);
79 | m.setCallbackId(jsonObject.has(CALLBACK_ID_STR) ? jsonObject.getString(CALLBACK_ID_STR):null);
80 | m.setResponseData(jsonObject.has(RESPONSE_DATA_STR) ? jsonObject.getString(RESPONSE_DATA_STR):null);
81 | m.setResponseId(jsonObject.has(RESPONSE_ID_STR) ? jsonObject.getString(RESPONSE_ID_STR):null);
82 | m.setData(jsonObject.has(DATA_STR) ? jsonObject.getString(DATA_STR):null);
83 | return m;
84 | } catch (JSONException e) {
85 | e.printStackTrace();
86 | }
87 | return m;
88 | }
89 |
90 | public static List toArrayList(String jsonStr){
91 | List list = new ArrayList();
92 | try {
93 | JSONArray jsonArray = new JSONArray(jsonStr);
94 | for(int i = 0; i < jsonArray.length(); i++){
95 | Message m = new Message();
96 | JSONObject jsonObject = jsonArray.getJSONObject(i);
97 | m.setHandlerName(jsonObject.has(HANDLER_NAME_STR) ? jsonObject.getString(HANDLER_NAME_STR):null);
98 | m.setCallbackId(jsonObject.has(CALLBACK_ID_STR) ? jsonObject.getString(CALLBACK_ID_STR):null);
99 | m.setResponseData(jsonObject.has(RESPONSE_DATA_STR) ? jsonObject.getString(RESPONSE_DATA_STR):null);
100 | m.setResponseId(jsonObject.has(RESPONSE_ID_STR) ? jsonObject.getString(RESPONSE_ID_STR):null);
101 | m.setData(jsonObject.has(DATA_STR) ? jsonObject.getString(DATA_STR):null);
102 | list.add(m);
103 | }
104 | } catch (JSONException e) {
105 | e.printStackTrace();
106 | }
107 | return list;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/WebChromeClientListener.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import android.graphics.Bitmap;
4 | import android.net.Uri;
5 | import android.os.Message;
6 | import android.view.View;
7 |
8 | import com.tencent.smtt.export.external.interfaces.ConsoleMessage;
9 | import com.tencent.smtt.export.external.interfaces.GeolocationPermissionsCallback;
10 | import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
11 | import com.tencent.smtt.export.external.interfaces.JsPromptResult;
12 | import com.tencent.smtt.export.external.interfaces.JsResult;
13 | import com.tencent.smtt.sdk.ValueCallback;
14 | import com.tencent.smtt.sdk.WebChromeClient;
15 | import com.tencent.smtt.sdk.WebStorage;
16 | import com.tencent.smtt.sdk.WebView;
17 |
18 | /**
19 | */
20 | public class WebChromeClientListener implements OnWebChromeClientListener {
21 |
22 | @Override
23 | public void onReceivedTitle(WebView view, String title) {
24 |
25 | }
26 |
27 | @Override
28 | public void onProgressChanged(WebView view, int newProgress) {
29 |
30 | }
31 |
32 | @Override
33 | public void onExceededDatabaseQuota(String url, String databaseIdentifier, long quota, long estimatedDatabaseSize, long totalQuota, WebStorage.QuotaUpdater quotaUpdater) {
34 |
35 | }
36 |
37 | @Override
38 | public Bitmap getDefaultVideoPoster() {
39 | return null;
40 | }
41 |
42 | @Override
43 | public void getVisitedHistory(ValueCallback valueCallback) {
44 |
45 | }
46 |
47 | @Override
48 | public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
49 | return false;
50 | }
51 |
52 | @Override
53 | public boolean onCreateWindow(WebView webView, boolean isDialog, boolean isUserGesture, Message message) {
54 | return false;
55 | }
56 |
57 | @Override
58 | public void onGeolocationPermissionsHidePrompt() {
59 |
60 | }
61 |
62 | @Override
63 | public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissionsCallback geolocationPermissionsCallback) {
64 |
65 | }
66 |
67 | @Override
68 | public void onHideCustomView() {
69 |
70 | }
71 |
72 | @Override
73 | public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
74 | return false;
75 | }
76 |
77 | @Override
78 | public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
79 | return false;
80 | }
81 |
82 | @Override
83 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
84 | return false;
85 | }
86 |
87 | @Override
88 | public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
89 | return false;
90 | }
91 |
92 | @Override
93 | public boolean onJsTimeout() {
94 | return false;
95 | }
96 |
97 | @Override
98 | public void onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater) {
99 |
100 | }
101 |
102 | @Override
103 | public void onReceivedIcon(WebView webView, Bitmap bitmap) {
104 |
105 | }
106 |
107 | @Override
108 | public void onReceivedTouchIconUrl(WebView webView, String url, boolean precomposed) {
109 |
110 | }
111 |
112 | @Override
113 | public void onRequestFocus(WebView webView) {
114 |
115 | }
116 |
117 | @Override
118 | public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback) {
119 |
120 | }
121 |
122 | @Override
123 | public void onShowCustomView(View view, int requestedOrientation, IX5WebChromeClient.CustomViewCallback customViewCallback) {
124 |
125 | }
126 |
127 | @Override
128 | public void onCloseWindow(WebView webView) {
129 |
130 | }
131 |
132 | @Override
133 | public View getVideoLoadingProgressView() {
134 | return null;
135 | }
136 |
137 | @Override
138 | public void openFileChooser(ValueCallback valueCallback, String s, String s1) {
139 |
140 | }
141 |
142 | @Override
143 | public boolean onShowFileChooser(WebView webView, ValueCallback valueCallback, WebChromeClient.FileChooserParams fileChooserParams) {
144 | return false;
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/BridgeUtil.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 |
6 | import com.tencent.smtt.sdk.WebView;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.InputStreamReader;
12 |
13 | public class BridgeUtil {
14 | final static String YY_OVERRIDE_SCHEMA = "yy://";
15 | final static String YY_RETURN_DATA = YY_OVERRIDE_SCHEMA + "return/";//格式为 yy://return/{function}/returncontent
16 | final static String YY_FETCH_QUEUE = YY_RETURN_DATA + "_fetchQueue/";
17 | final static String EMPTY_STR = "";
18 | final static String UNDERLINE_STR = "_";
19 | final static String SPLIT_MARK = "/";
20 |
21 | final static String CALLBACK_ID_FORMAT = "JAVA_CB_%s";
22 | final static String JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');";
23 | final static String JS_FETCH_QUEUE_FROM_JAVA = "javascript:WebViewJavascriptBridge._fetchQueue();";
24 | public final static String JAVASCRIPT_STR = "javascript:";
25 |
26 | public static String parseFunctionName(String jsUrl, String customJs) {
27 | return jsUrl.replace("javascript:" + customJs + ".", "").replaceAll("\\(.*\\);", "");
28 | }
29 |
30 | public static String getDataFromReturnUrl(String url) {
31 | if (url.startsWith(YY_FETCH_QUEUE)) {
32 | return url.replace(YY_FETCH_QUEUE, EMPTY_STR);
33 | }
34 |
35 | String temp = url.replace(YY_RETURN_DATA, EMPTY_STR);
36 | String[] functionAndData = temp.split(SPLIT_MARK);
37 |
38 | if (functionAndData.length >= 2) {
39 | StringBuilder sb = new StringBuilder();
40 | for (int i = 1; i < functionAndData.length; i++) {
41 | sb.append(functionAndData[i]);
42 | }
43 | return sb.toString();
44 | }
45 | return null;
46 | }
47 |
48 | public static String getFunctionFromReturnUrl(String url) {
49 | String temp = url.replace(YY_RETURN_DATA, EMPTY_STR);
50 | String[] functionAndData = temp.split(SPLIT_MARK);
51 | if (functionAndData.length >= 1) {
52 | return functionAndData[0];
53 | }
54 | return null;
55 | }
56 |
57 |
58 | /**
59 | * js 文件将注入为第一个script引用
60 | *
61 | * @param view webview
62 | * @param url url
63 | */
64 | public static void webViewLoadJs(WebView view, String url) {
65 | String js = "var newscript = document.createElement(\"script\");";
66 | js += "newscript.src=\"" + url + "\";";
67 | js += "document.scripts[0].parentNode.insertBefore(newscript,document.scripts[0]);";
68 | view.loadUrl("javascript:" + js);
69 | }
70 |
71 | public static void webViewLoadLocalJs(WebView view, String path) {
72 | String jsContent = assetFile2Str(view.getContext(), path);
73 | view.loadUrl("javascript:" + jsContent);
74 | }
75 |
76 | public static void webViewLoadLocalJs(WebView view, String path, String defaultJs, String customJs) {
77 | String jsContent = assetFile2Str(view.getContext(), path);
78 | if (!TextUtils.isEmpty(jsContent)) {
79 | jsContent = jsContent.replaceAll(defaultJs, customJs);
80 | }
81 | view.loadUrl("javascript:" + jsContent);
82 | }
83 |
84 | public static String assetFile2Str(Context c, String urlStr) {
85 | InputStream in = null;
86 | try {
87 | in = c.getAssets().open(urlStr);
88 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
89 | String line = null;
90 | StringBuilder sb = new StringBuilder();
91 | do {
92 | line = bufferedReader.readLine();
93 | if (line != null && !line.matches("^\\s*\\/\\/.*")) {
94 | sb.append(line);
95 | }
96 | } while (line != null);
97 |
98 | bufferedReader.close();
99 | in.close();
100 |
101 | return sb.toString();
102 | } catch (Exception e) {
103 | e.printStackTrace();
104 | } finally {
105 | if (in != null) {
106 | try {
107 | in.close();
108 | } catch (IOException e) {
109 | }
110 | }
111 | }
112 | return null;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/FileDisplayActivity.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.os.Environment;
8 | import android.support.annotation.Nullable;
9 | import android.util.Log;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.LinearLayout;
13 | import android.widget.RelativeLayout;
14 | import android.widget.TextView;
15 |
16 | import com.lzy.okgo.OkGo;
17 | import com.lzy.okgo.callback.FileCallback;
18 | import com.lzy.okgo.model.Progress;
19 | import com.lzy.okgo.model.Response;
20 | import com.tencent.smtt.sdk.TbsReaderView;
21 |
22 | import java.io.File;
23 |
24 | /**
25 | * Project : yunaandroid.
26 | * Package name: com.renwei.yunlong.activity
27 | * Created by : Benjamin.
28 | * Created time: 2017/11/24 10:58
29 | * Changed by : Benjamin.
30 | * Changed time: 2017/11/24 10:58
31 | * Class description:
32 | */
33 |
34 | public class FileDisplayActivity extends Activity implements TbsReaderView.ReaderCallback {
35 | private final String TAG = "FileDisplayActivity";
36 | TextView tvInformation;
37 | LinearLayout tbsParent;
38 | private TbsReaderView mTbsReaderView;
39 |
40 |
41 | @Override
42 | protected void onCreate(@Nullable Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_file_display);
45 | String path = getIntent().getStringExtra("path") == null ? "" : getIntent().getStringExtra("path");
46 | tbsParent = findViewById(R.id.tbsParent);
47 | tvInformation = findViewById(R.id.tv_information);
48 | tbsParent = findViewById(R.id.tbsParent);
49 | mTbsReaderView = new TbsReaderView(this, FileDisplayActivity.this);
50 | tbsParent.addView(mTbsReaderView, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
51 | downloadFile(path);
52 | }
53 |
54 | private void openFile(String absPath) {
55 | final File file = new File(absPath);
56 | if (file.exists()) {
57 | //显示文件
58 | final Bundle bundle = new Bundle();
59 | bundle.putString("filePath", absPath);
60 | bundle.putString("tempPath", Environment.getExternalStorageDirectory().getPath());
61 | String pathFormat = parseFormat(absPath);
62 | boolean result = mTbsReaderView.preOpen(pathFormat, false);
63 | Log.e(TAG, String.valueOf(file.getName()) + "文件格式:" + pathFormat + "预加载结果" + result);
64 | if (result) {
65 | tvInformation.setVisibility(View.GONE);
66 | mTbsReaderView.openFile(bundle);
67 | } else {
68 | tvInformation.setVisibility(View.VISIBLE);
69 | tvInformation.setText("不支持的文件格式");
70 | }
71 |
72 | } else {
73 | tvInformation.setVisibility(View.VISIBLE);
74 | tvInformation.setText("文件不存在");
75 | }
76 | }
77 |
78 | //获取文件的格式判断文件是否支持 这里文件是不需要带.的 ******
79 | private String parseFormat(String fileName) {
80 | return fileName.substring(fileName.lastIndexOf(".") + 1);
81 | }
82 |
83 | @Override
84 | protected void onDestroy() {
85 | super.onDestroy();
86 | mTbsReaderView.onStop();
87 | tbsParent.removeView(mTbsReaderView);
88 | }
89 |
90 | private void downloadFile(String url) {
91 | File file = new File(url);
92 | String fileName = file.getName();
93 | String localFileName = getCacheDir().getAbsolutePath() + fileName;
94 | File localFile = new File(localFileName);
95 | if (localFile.exists()) {
96 | openFile(localFile.getAbsolutePath());
97 | return;
98 | }
99 | OkGo.get(url).tag(this).execute(new FileCallback(getCacheDir().getAbsolutePath(), fileName) {
100 | @Override
101 | public void onSuccess(Response response) {
102 | Log.e(TAG, "onSuccess: 下载成功");
103 | if (response.body().exists()) {
104 | openFile(response.body().getAbsolutePath());
105 | }
106 | }
107 |
108 | @Override
109 | public void onError(Response response) {
110 | Log.e(TAG, "onError:downloadProgress ---" + response.getException().getMessage());
111 | Log.e(TAG, "onError: 下载失败");
112 | }
113 |
114 | @Override
115 | public void downloadProgress(Progress progress) {
116 | Log.e(TAG, "onError:downloadProgress ---" + progress.currentSize);
117 | }
118 | });
119 | }
120 |
121 | @Override
122 | public void onCallBackAction(Integer integer, Object o, Object o1) {
123 |
124 | }
125 |
126 | public static void openActivity(Context context, String url) {
127 | Intent intent = new Intent(context, FileDisplayActivity.class);
128 | intent.putExtra("path", url);
129 | context.startActivity(intent);
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/MainActivity.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.widget.Button;
9 |
10 | import com.tencent.smtt.sdk.TbsMediaPlayer;
11 | import com.tencent.smtt.sdk.TbsVideo;
12 | import com.tencent.smtt.sdk.ValueCallback;
13 |
14 | /**
15 | * Project : TBSreader.
16 | * Package name: github.benjamin.tbsreader
17 | * Created by : Benjamin.
18 | * Created time: 2018/1/3 10:33
19 | * Changed by : Benjamin.
20 | * Changed time: 2018/1/3 10:33
21 | * Class description:
22 | */
23 |
24 | public class MainActivity extends Activity implements View.OnClickListener, TbsMediaPlayer.TbsMediaPlayerListener, ValueCallback {
25 |
26 |
27 | private Button mBrowserOpen;
28 | private Button mWordOpen;
29 | private Button mExcellOpen;
30 | private Button mPdfOpen;
31 | private Button mVideoOpen;
32 | private Button mMusicOpen;
33 |
34 | @Override
35 | protected void onCreate(@Nullable Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.activity_main);
38 | initView();
39 |
40 | }
41 |
42 | private void initView() {
43 |
44 | mBrowserOpen = findViewById(R.id.open_browser);
45 | mBrowserOpen.setOnClickListener(this);
46 | mWordOpen = findViewById(R.id.open_word);
47 | mWordOpen.setOnClickListener(this);
48 | mExcellOpen = findViewById(R.id.open_excell);
49 | mExcellOpen.setOnClickListener(this);
50 | mPdfOpen = findViewById(R.id.open_pdf);
51 | mPdfOpen.setOnClickListener(this);
52 | mVideoOpen = (Button) findViewById(R.id.open_video);
53 | mVideoOpen.setOnClickListener(this);
54 | mMusicOpen = (Button) findViewById(R.id.open_music);
55 | mMusicOpen.setOnClickListener(this);
56 | }
57 |
58 | @Override
59 | public void onClick(View v) {
60 | switch (v.getId()) {
61 | case R.id.open_browser:
62 | WebBrowserActivity.openActivity(this);
63 | break;
64 | case R.id.open_word:// TODO 18/01/09
65 | FileDisplayActivity.openActivity(this, "http://www.dabinDev.cn/file/123doc.doc");
66 | break;
67 | case R.id.open_excell:// TODO 18/01/09
68 | FileDisplayActivity.openActivity(this, "http://www.dabinDev.cn/file/123xls.xls");
69 | break;
70 | case R.id.open_pdf:// TODO 18/01/09
71 | FileDisplayActivity.openActivity(this, "http://www.dabinDev.cn/file/123pdf.pdf");
72 | break;
73 | case R.id.open_music:// TODO 18/01/09
74 | /*TbsMediaFactory factory = new TbsMediaFactory(this);
75 | TbsMediaPlayer player = factory.createPlayer();
76 | if (player.isAvailable()) {
77 | player.setVolume(1f);
78 | player.startPlay("http://www.dabinDev.cn/file/123hope.mp3", new Bundle());
79 | player.setPlayerListener(this);
80 | }*/
81 | Bundle mp3Data = new Bundle();
82 | mp3Data.putInt("screenMode", 102);
83 | mp3Data.putBoolean("supportLiteWnd", false);
84 | TbsVideo.openVideo(this, "http://www.dabinDev.cn/file/12312312.mp4", mp3Data);
85 | break;
86 | case R.id.open_video:// TODO 18/01/09
87 | Bundle extraData = new Bundle();
88 | extraData.putInt("screenMode", 102);
89 | extraData.putBoolean("supportLiteWnd", false);
90 | TbsVideo.openVideo(this, "http://www.dabinDev.cn/file/12312312.mp4", extraData);
91 | break;
92 | default:
93 | break;
94 | }
95 | }
96 |
97 | @Override
98 | public void onPlayerPrepared(long l, int i, int i1, int i2, int i3) {
99 | Log.e("audio", "onPlayerPrepared");
100 |
101 | }
102 |
103 | @Override
104 | public void onPlayerExtra(int i, Object o) {
105 | Log.e("audio", "onPlayerExtra");
106 |
107 | }
108 |
109 | @Override
110 | public void onPlayerError(String s, int i, int i1, Throwable throwable) {
111 | Log.e("audio", "onPlayerError");
112 |
113 | }
114 |
115 | @Override
116 | public void onPlayerInfo(int i, int i1) {
117 | Log.e("audio", "onPlayerInfo");
118 |
119 | }
120 |
121 | @Override
122 | public void onPlayerPlaying() {
123 | Log.e("audio", "onPlayerPlaying");
124 |
125 | }
126 |
127 | @Override
128 | public void onPlayerProgress(long l) {
129 | Log.e("audio", "onPlayerProgress");
130 |
131 | }
132 |
133 | @Override
134 | public void onPlayerSubtitle(String s) {
135 | Log.e("audio", "onPlayerSubtitle");
136 |
137 | }
138 |
139 | @Override
140 | public void onPlayerPaused() {
141 | Log.e("audio", "onPlayerPaused");
142 |
143 | }
144 |
145 | @Override
146 | public void onPlayerSeeked(long l) {
147 | Log.e("audio", "onPlayerSeeked");
148 |
149 | }
150 |
151 | @Override
152 | public void onPlayerCompleted() {
153 | Log.e("audio", "onPlayerCompleted");
154 |
155 | }
156 |
157 | @Override
158 | public void onBufferingUpdate(float v) {
159 | Log.e("audio", "onBufferingUpdate");
160 |
161 | }
162 |
163 | @Override
164 | public void onReceiveValue(Boolean aBoolean) {
165 |
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/app/src/main/assets/WebViewJavascriptBridge.js:
--------------------------------------------------------------------------------
1 | //notation: js file can only use this kind of comments
2 | //since comments will cause error when use in webview.loadurl,
3 | //comments will be remove by java use regexp
4 | (function() {
5 | if (window.WebViewJavascriptBridge) {
6 | return;
7 | }
8 |
9 | var messagingIframe;
10 | var sendMessageQueue = [];
11 | var receiveMessageQueue = [];
12 | var messageHandlers = {};
13 |
14 | var CUSTOM_PROTOCOL_SCHEME = 'yy';
15 | var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/';
16 |
17 | var responseCallbacks = {};
18 | var uniqueId = 1;
19 |
20 | function _createQueueReadyIframe(doc) {
21 | messagingIframe = doc.createElement('iframe');
22 | messagingIframe.style.display = 'none';
23 | doc.documentElement.appendChild(messagingIframe);
24 | }
25 |
26 | //set default messageHandler
27 | function init(messageHandler) {
28 | if (WebViewJavascriptBridge._messageHandler) {
29 | throw new Error('WebViewJavascriptBridge.init called twice');
30 | }
31 | WebViewJavascriptBridge._messageHandler = messageHandler;
32 | var receivedMessages = receiveMessageQueue;
33 | receiveMessageQueue = null;
34 | for (var i = 0; i < receivedMessages.length; i++) {
35 | _dispatchMessageFromNative(receivedMessages[i]);
36 | }
37 | }
38 |
39 | function send(data, responseCallback) {
40 | _doSend({
41 | data: data
42 | }, responseCallback);
43 | }
44 |
45 | function registerHandler(handlerName, handler) {
46 | messageHandlers[handlerName] = handler;
47 | }
48 |
49 | function callHandler(handlerName, data, responseCallback) {
50 | _doSend({
51 | handlerName: handlerName,
52 | data: data
53 | }, responseCallback);
54 | }
55 |
56 | //sendMessage add message, 触发native处理 sendMessage
57 | function _doSend(message, responseCallback) {
58 | if (responseCallback) {
59 | var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime();
60 | responseCallbacks[callbackId] = responseCallback;
61 | message.callbackId = callbackId;
62 | }
63 |
64 | sendMessageQueue.push(message);
65 | messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
66 | }
67 |
68 | // 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容
69 | function _fetchQueue() {
70 | var messageQueueString = JSON.stringify(sendMessageQueue);
71 | sendMessageQueue = [];
72 | //android can't read directly the return data, so we can reload iframe src to communicate with java
73 | messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
74 | }
75 |
76 | //提供给native使用,
77 | function _dispatchMessageFromNative(messageJSON) {
78 | setTimeout(function() {
79 | var message = JSON.parse(messageJSON);
80 | var responseCallback;
81 | //java call finished, now need to call js callback function
82 | if (message.responseId) {
83 | responseCallback = responseCallbacks[message.responseId];
84 | if (!responseCallback) {
85 | return;
86 | }
87 | responseCallback(message.responseData);
88 | delete responseCallbacks[message.responseId];
89 | } else {
90 | //直接发送
91 | if (message.callbackId) {
92 | var callbackResponseId = message.callbackId;
93 | responseCallback = function(responseData) {
94 | _doSend({
95 | responseId: callbackResponseId,
96 | responseData: responseData
97 | });
98 | };
99 | }
100 |
101 | var handler = WebViewJavascriptBridge._messageHandler;
102 | if (message.handlerName) {
103 | handler = messageHandlers[message.handlerName];
104 | }
105 | //查找指定handler
106 | try {
107 | handler(message.data, responseCallback);
108 | } catch (exception) {
109 | if (typeof console != 'undefined') {
110 | console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception);
111 | }
112 | }
113 | }
114 | });
115 | }
116 |
117 | //提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以
118 | function _handleMessageFromNative(messageJSON) {
119 | console.log(messageJSON);
120 | if (receiveMessageQueue) {
121 | receiveMessageQueue.push(messageJSON);
122 | } else {
123 | _dispatchMessageFromNative(messageJSON);
124 | }
125 | }
126 |
127 | var WebViewJavascriptBridge = window.WebViewJavascriptBridge = {
128 | init: init,
129 | send: send,
130 | registerHandler: registerHandler,
131 | callHandler: callHandler,
132 | _fetchQueue: _fetchQueue,
133 | _handleMessageFromNative: _handleMessageFromNative
134 | };
135 |
136 | var doc = document;
137 | _createQueueReadyIframe(doc);
138 | var readyEvent = doc.createEvent('Events');
139 | readyEvent.initEvent('WebViewJavascriptBridgeReady');
140 | readyEvent.bridge = WebViewJavascriptBridge;
141 | doc.dispatchEvent(readyEvent);
142 | })();
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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/java/github/benjamin/tbsreader/WebBrowserActivity.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.graphics.Bitmap;
8 | import android.graphics.PixelFormat;
9 | import android.os.Bundle;
10 | import android.support.annotation.Nullable;
11 | import android.support.v7.app.AlertDialog;
12 | import android.util.Log;
13 | import android.view.View;
14 | import android.view.WindowManager;
15 | import android.webkit.JavascriptInterface;
16 | import android.widget.Button;
17 | import android.widget.Toast;
18 |
19 | import com.tencent.smtt.export.external.interfaces.SslError;
20 | import com.tencent.smtt.export.external.interfaces.SslErrorHandler;
21 | import com.tencent.smtt.sdk.WebChromeClient;
22 | import com.tencent.smtt.sdk.WebSettings;
23 | import com.tencent.smtt.sdk.WebView;
24 |
25 | import github.benjamin.tbsreader.bridge.BridgeHandler;
26 | import github.benjamin.tbsreader.bridge.CallBackFunction;
27 | import github.benjamin.tbsreader.bridge.DefaultHandler;
28 | import github.benjamin.tbsreader.bridge.SimpleBridgeWebViewClientListener;
29 | import github.benjamin.tbsreader.bridge.TbsBridgeWebView;
30 |
31 | /**
32 | * Project : TBSreader.
33 | * Package name: github.benjamin.tbsreader
34 | * Created by : Benjamin.
35 | * Created time: 2018/1/3 15:36
36 | * Changed by : Benjamin.
37 | * Changed time: 2018/1/3 15:36
38 | * Class description:
39 | */
40 |
41 | public class WebBrowserActivity extends Activity {
42 | private String file;
43 | TbsBridgeWebView webView;
44 | private String TAG = "WebBrowserActivity";
45 | private Button mAndroidCallJs;
46 |
47 | @Override
48 | protected void onCreate(@Nullable Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | setContentView(R.layout.activity_web_browser);
51 | getWindow().setFormat(PixelFormat.TRANSLUCENT);//(这个对宿主没什么影响,建议声明)
52 | getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
53 | file = getIntent().getStringExtra("filePath") == null ? "" : getIntent().getStringExtra("filePath");
54 | initView();
55 | }
56 |
57 | @SuppressWarnings("deprecation")
58 | @JavascriptInterface
59 | private void initView() {
60 | webView = findViewById(R.id.webView);
61 | mAndroidCallJs = findViewById(R.id.androidCallJs);
62 | webView.getSettings().setJavaScriptEnabled(true);
63 | webView.getSettings().setSaveFormData(false);
64 | webView.getSettings().setSavePassword(false);
65 | webView.getSettings().setSupportZoom(true);
66 | webView.getSettings().setDomStorageEnabled(true);
67 | webView.getSettings().setBuiltInZoomControls(true);
68 | webView.getSettings().setDisplayZoomControls(false);
69 | webView.getSettings().setLoadWithOverviewMode(true);
70 | //设定支持h5viewport
71 | webView.getSettings().setUseWideViewPort(true);
72 | // 自适应屏幕.
73 | webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
74 | webView.setBridgeWebViewClientListener(new SimpleBridgeWebViewClientListener());
75 | //=======================此方法必须调用==========================
76 | webView.setDefaultHandler(new DefaultHandler());
77 | //=======================js桥使用改方法替换原有setWebViewClient()方法==========================
78 | //=======================js桥使用改方法替换原有setWebViewClient()方法==========================
79 |
80 | webView.setBridgeWebViewClientListener(new SimpleBridgeWebViewClientListener() {
81 |
82 | @Override
83 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
84 | Log.i(TAG, "超链接:" + url);
85 | return false;
86 | }
87 |
88 | @Override
89 | public void onPageStarted(WebView view, String url, Bitmap bitmap) {
90 |
91 | }
92 |
93 | @Override
94 | public void onPageFinished(WebView view, String url) {
95 |
96 |
97 | }
98 |
99 | @Override
100 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
101 |
102 | }
103 |
104 | @Override
105 | public boolean onReceivedSslError(WebView webView, final SslErrorHandler sslErrorHandler, SslError sslError) {
106 | String message;
107 | switch (sslError.getPrimaryError()) {
108 | case android.net.http.SslError.SSL_UNTRUSTED:
109 | message = "证书颁发机构不受信任";
110 | break;
111 | case android.net.http.SslError.SSL_EXPIRED:
112 | message = "证书过期";
113 | break;
114 | case android.net.http.SslError.SSL_IDMISMATCH:
115 | message = "网站名称与证书不一致";
116 | break;
117 | case android.net.http.SslError.SSL_NOTYETVALID:
118 | message = "证书无效";
119 | break;
120 | case android.net.http.SslError.SSL_DATE_INVALID:
121 | message = "证书日期无效";
122 | break;
123 | case android.net.http.SslError.SSL_INVALID:
124 | default:
125 | message = "证书错误";
126 | break;
127 | }
128 | AlertDialog.Builder builder = new AlertDialog.Builder(WebBrowserActivity.this);
129 | builder.setTitle("提示").setMessage(message + ",是否继续").setCancelable(true)
130 | .setPositiveButton("确认", new DialogInterface.OnClickListener() {
131 | @Override
132 | public void onClick(DialogInterface dialog, int id) {
133 | sslErrorHandler.proceed();
134 | }
135 | })
136 | .setNegativeButton("取消", new DialogInterface.OnClickListener() {
137 | @Override
138 | public void onClick(DialogInterface dialog, int id) {
139 | sslErrorHandler.cancel();
140 | }
141 | });
142 | AlertDialog alert = builder.create();
143 | alert.show();
144 | return true;
145 | }
146 | });
147 | //=======================此方法必须调用==========================
148 | webView.setDefaultHandler(new DefaultHandler());
149 | webView.setWebChromeClient(new WebChromeClient() {
150 | @Override
151 | public void onReceivedTitle(WebView view, String title) {
152 | super.onReceivedTitle(view, title);
153 | }
154 |
155 | @Override
156 | public void onProgressChanged(WebView view, int newProgress) {
157 | // TODO Auto-generated method stub
158 | super.onProgressChanged(view, newProgress);
159 | }
160 | });
161 |
162 | webView.loadUrl(file);
163 |
164 |
165 | // webView.setCustom("桥名");
166 | webView.setCustom("TestJavascriptBridge");
167 |
168 | //=======================以下4个web调用native示例方法==========================
169 | webView.registerHandler("jsCallPhone", new BridgeHandler() {
170 | @Override
171 | public void handler(String data, CallBackFunction function) {
172 | Log.i(TAG, "回传结果:" + data);
173 | Toast.makeText(WebBrowserActivity.this, data, Toast.LENGTH_LONG).show();
174 | }
175 | });
176 | mAndroidCallJs.setOnClickListener(new View.OnClickListener() {
177 | @Override
178 | public void onClick(View v) {//写死的字符串需要注意
179 | String message = "javascript:phoneCallJs(\"" + "你好 大胡子" + "\")";//需要放到pagefind里面或者在loadurl后面否则会返回null
180 | webView.loadUrl(message);
181 | }
182 | });
183 |
184 | }
185 |
186 | public static void openActivity(Context context) {
187 | Intent intent = new Intent(context, WebBrowserActivity.class);
188 | intent.putExtra("filePath", "http://www.dabinDev.cn/Bridge/test.html");
189 | context.startActivity(intent);
190 | }
191 |
192 | public static void openActivity(Context context,String file) {
193 | Intent intent = new Intent(context, WebBrowserActivity.class);
194 | intent.putExtra("filePath", file);
195 | context.startActivity(intent);
196 | }
197 |
198 | @Override
199 | public void onBackPressed() {
200 | if (webView != null) {
201 | if (webView.canGoBack()) {
202 | webView.goBack();
203 | } else {
204 | finish();
205 | }
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/BridgeWebViewClient.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Bundle;
5 | import android.view.KeyEvent;
6 |
7 | import com.tencent.smtt.export.external.interfaces.ClientCertRequest;
8 | import com.tencent.smtt.export.external.interfaces.HttpAuthHandler;
9 | import com.tencent.smtt.export.external.interfaces.SslError;
10 | import com.tencent.smtt.export.external.interfaces.SslErrorHandler;
11 | import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
12 | import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
13 | import com.tencent.smtt.sdk.WebView;
14 | import com.tencent.smtt.sdk.WebViewClient;
15 |
16 | import java.io.UnsupportedEncodingException;
17 | import java.net.URLDecoder;
18 |
19 | public class BridgeWebViewClient extends WebViewClient {
20 | private TbsBridgeWebView webView;
21 | /**
22 | * 是否重定向,避免web为渲染即跳转导致系统未调用onPageStarted就调用onPageFinished方法引起的js桥初始化失败
23 | */
24 | private boolean isRedirected;
25 | /**
26 | * onPageStarted连续调用次数,避免渲染立马跳转可能连续调用onPageStarted多次并且调用shouldOverrideUrlLoading后不调用onPageStarted引起的js桥未初始化问题
27 | */
28 | private int onPageStartedCount = 0;
29 | private BridgeWebViewClientListener bridgeWebViewClientListener;
30 |
31 | public BridgeWebViewClient(TbsBridgeWebView webView) {
32 | this.webView = webView;
33 | }
34 |
35 | public void setBridgeWebViewClientListener(BridgeWebViewClientListener bridgeWebViewClientListener) {
36 | this.bridgeWebViewClientListener = bridgeWebViewClientListener;
37 | }
38 |
39 | public void removeListener() {
40 | if (bridgeWebViewClientListener != null) {
41 | bridgeWebViewClientListener = null;
42 | }
43 | }
44 |
45 | @Override
46 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
47 | //modify:hjhrq1991,web为渲染即跳转导致系统未调用onPageStarted就调用onPageFinished方法引起的js桥初始化失败
48 | if (onPageStartedCount < 2) {
49 | isRedirected = true;
50 | }
51 | onPageStartedCount = 0;
52 |
53 | try {
54 | url = URLDecoder.decode(url, "UTF-8");
55 | } catch (UnsupportedEncodingException e) {
56 | e.printStackTrace();
57 | }
58 |
59 | if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { // 如果是返回数据
60 | webView.handlerReturnData(url);
61 | return true;
62 | } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { //
63 | webView.flushMessageQueue();
64 | return true;
65 | } else {
66 | if (bridgeWebViewClientListener != null) {
67 | return bridgeWebViewClientListener.shouldOverrideUrlLoading(view, url);
68 | } else {
69 | return super.shouldOverrideUrlLoading(view, url);
70 | }
71 | }
72 | }
73 |
74 | @Override
75 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
76 | super.onPageStarted(view, url, favicon);
77 | //modify:hjhrq1991,web为渲染即跳转导致系统未调用onPageStarted就调用onPageFinished方法引起的js桥初始化失败
78 | isRedirected = false;
79 | onPageStartedCount++;
80 |
81 | if (bridgeWebViewClientListener != null) {
82 | bridgeWebViewClientListener.onPageStarted(view, url, favicon);
83 | }
84 | }
85 |
86 | @Override
87 | public void onPageFinished(WebView view, String url) {
88 | //modify:hjhrq1991,web为渲染即跳转导致系统未调用onPageStarted就调用onPageFinished方法引起的js桥初始化失败
89 | if (BridgeConfig.toLoadJs != null && !url.contains("about:blank") && !isRedirected) {
90 | BridgeUtil.webViewLoadLocalJs(view, BridgeConfig.toLoadJs, BridgeConfig.defaultJs, BridgeConfig.customJs);
91 | }
92 |
93 | if (webView.getStartupMessage() != null) {
94 | for (Message m : webView.getStartupMessage()) {
95 | webView.dispatchMessage(m);
96 | }
97 | webView.setStartupMessage(null);
98 | }
99 |
100 | if (bridgeWebViewClientListener != null) {
101 | bridgeWebViewClientListener.onPageFinished(view, url);
102 | }
103 | }
104 |
105 | @Override
106 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
107 | if (bridgeWebViewClientListener != null) {
108 | bridgeWebViewClientListener.onReceivedError(view, errorCode, description, failingUrl);
109 | }
110 | }
111 |
112 | @Override
113 | public void onLoadResource(WebView webView, String s) {
114 | if (bridgeWebViewClientListener != null) {
115 | bridgeWebViewClientListener.onLoadResource(webView, s);
116 | }
117 | }
118 |
119 | @Override
120 | public void onReceivedHttpError(WebView webView, WebResourceRequest webResourceRequest, WebResourceResponse webResourceResponse) {
121 | if (bridgeWebViewClientListener != null) {
122 | bridgeWebViewClientListener.onReceivedHttpError(webView, webResourceRequest, webResourceResponse);
123 | }
124 | }
125 |
126 | @Override
127 | public WebResourceResponse shouldInterceptRequest(WebView webView, String s) {
128 | if (bridgeWebViewClientListener != null) {
129 | return bridgeWebViewClientListener.shouldInterceptRequest(webView, s);
130 | } else {
131 | return super.shouldInterceptRequest(webView, s);
132 | }
133 | }
134 |
135 | @Override
136 | public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest) {
137 | if (bridgeWebViewClientListener != null) {
138 | return bridgeWebViewClientListener.shouldInterceptRequest(webView, webResourceRequest);
139 | } else {
140 | return super.shouldInterceptRequest(webView, webResourceRequest);
141 | }
142 | }
143 |
144 | @Override
145 | public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest, Bundle bundle) {
146 | if (bridgeWebViewClientListener != null) {
147 | return bridgeWebViewClientListener.shouldInterceptRequest(webView, webResourceRequest, bundle);
148 | } else {
149 | return super.shouldInterceptRequest(webView, webResourceRequest, bundle);
150 | }
151 | }
152 |
153 | @Override
154 | public void doUpdateVisitedHistory(WebView webView, String s, boolean b) {
155 | if (bridgeWebViewClientListener != null) {
156 | bridgeWebViewClientListener.doUpdateVisitedHistory(webView, s, b);
157 | }
158 | }
159 |
160 | @Override
161 | public void onFormResubmission(WebView webView, android.os.Message message, android.os.Message message1) {
162 | boolean interrupt = false;
163 | if (bridgeWebViewClientListener != null) {
164 | interrupt = bridgeWebViewClientListener.onFormResubmission(webView, message, message1);
165 | }
166 | if (!interrupt) {
167 | super.onFormResubmission(webView, message, message1);
168 | }
169 | }
170 |
171 | @Override
172 | public void onReceivedHttpAuthRequest(WebView webView, HttpAuthHandler httpAuthHandler, String s, String s1) {
173 | boolean interrupt = false;
174 | if (bridgeWebViewClientListener != null) {
175 | interrupt = bridgeWebViewClientListener.onReceivedHttpAuthRequest(webView, httpAuthHandler, s, s1);
176 | }
177 | if (!interrupt) {
178 | super.onReceivedHttpAuthRequest(webView, httpAuthHandler, s, s1);
179 | }
180 | }
181 |
182 | @Override
183 | public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
184 | boolean interrupt = false;
185 | if (bridgeWebViewClientListener != null) {
186 | interrupt = bridgeWebViewClientListener.onReceivedSslError(webView, sslErrorHandler, sslError);
187 | }
188 | if (!interrupt) {
189 | super.onReceivedSslError(webView, sslErrorHandler, sslError);
190 | }
191 | }
192 |
193 | @Override
194 | public void onReceivedClientCertRequest(WebView webView, ClientCertRequest clientCertRequest) {
195 | boolean interrupt = false;
196 | if (bridgeWebViewClientListener != null) {
197 | interrupt = bridgeWebViewClientListener.onReceivedClientCertRequest(webView, clientCertRequest);
198 | }
199 | if (!interrupt) {
200 | super.onReceivedClientCertRequest(webView, clientCertRequest);
201 | }
202 | }
203 |
204 | @Override
205 | public void onScaleChanged(WebView webView, float v, float v1) {
206 | if (bridgeWebViewClientListener != null) {
207 | bridgeWebViewClientListener.onScaleChanged(webView, v, v1);
208 | }
209 | }
210 |
211 | @Override
212 | public void onUnhandledKeyEvent(WebView webView, KeyEvent keyEvent) {
213 | if (bridgeWebViewClientListener != null) {
214 | bridgeWebViewClientListener.onUnhandledKeyEvent(webView, keyEvent);
215 | }
216 | }
217 |
218 | @Override
219 | public boolean shouldOverrideKeyEvent(WebView webView, KeyEvent keyEvent) {
220 | if (bridgeWebViewClientListener != null) {
221 | return bridgeWebViewClientListener.shouldOverrideKeyEvent(webView, keyEvent);
222 | } else {
223 | return super.shouldOverrideKeyEvent(webView, keyEvent);
224 | }
225 | }
226 |
227 | @Override
228 | public void onTooManyRedirects(WebView webView, android.os.Message message, android.os.Message message1) {
229 | if (bridgeWebViewClientListener != null) {
230 | bridgeWebViewClientListener.onTooManyRedirects(webView, message, message1);
231 | }
232 | }
233 |
234 | @Override
235 | public void onReceivedLoginRequest(WebView webView, String s, String s1, String s2) {
236 | if (bridgeWebViewClientListener != null) {
237 | bridgeWebViewClientListener.onReceivedLoginRequest(webView, s, s1, s2);
238 | }
239 | }
240 |
241 | @Override
242 | public void onDetectedBlankScreen(String s, int i) {
243 | if (bridgeWebViewClientListener != null) {
244 | bridgeWebViewClientListener.onDetectedBlankScreen(s, i);
245 | }
246 | }
247 | }
--------------------------------------------------------------------------------
/app/src/main/java/github/benjamin/tbsreader/bridge/TbsBridgeWebView.java:
--------------------------------------------------------------------------------
1 | package github.benjamin.tbsreader.bridge;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.net.Uri;
7 | import android.os.Build;
8 | import android.os.Looper;
9 | import android.os.SystemClock;
10 | import android.text.TextUtils;
11 | import android.util.AttributeSet;
12 | import android.view.View;
13 |
14 | import com.tencent.smtt.export.external.interfaces.ConsoleMessage;
15 | import com.tencent.smtt.export.external.interfaces.GeolocationPermissionsCallback;
16 | import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
17 | import com.tencent.smtt.export.external.interfaces.JsPromptResult;
18 | import com.tencent.smtt.export.external.interfaces.JsResult;
19 | import com.tencent.smtt.sdk.ValueCallback;
20 | import com.tencent.smtt.sdk.WebChromeClient;
21 | import com.tencent.smtt.sdk.WebStorage;
22 | import com.tencent.smtt.sdk.WebView;
23 |
24 | import java.util.ArrayList;
25 | import java.util.HashMap;
26 | import java.util.List;
27 | import java.util.Map;
28 |
29 | @SuppressLint("SetJavaScriptEnabled")
30 | public class TbsBridgeWebView extends WebView implements WebViewJavascriptBridge {
31 |
32 | private final String TAG = "BridgeWebView";
33 |
34 | private BridgeWebViewClient bridgeWebViewClient;
35 |
36 | Map responseCallbacks = new HashMap();
37 | Map messageHandlers = new HashMap();
38 | BridgeHandler defaultHandler = new DefaultHandler();
39 |
40 | private List startupMessage = new ArrayList();
41 |
42 | public List getStartupMessage() {
43 | return startupMessage;
44 | }
45 |
46 | public void setStartupMessage(List startupMessage) {
47 | this.startupMessage = startupMessage;
48 | }
49 |
50 | private long uniqueId = 0;
51 |
52 | public TbsBridgeWebView(Context context, AttributeSet attrs) {
53 | super(context, attrs);
54 | init();
55 | }
56 |
57 | public TbsBridgeWebView(Context context, AttributeSet attrs, int defStyle) {
58 | super(context, attrs, defStyle);
59 | init();
60 | }
61 |
62 | public TbsBridgeWebView(Context context) {
63 | super(context);
64 | init();
65 | }
66 |
67 | /**
68 | * @param handler default handler,handle messages send by js without assigned handler name,
69 | * if js message has handler name, it will be handled by named handlers registered by native
70 | */
71 | public void setDefaultHandler(BridgeHandler handler) {
72 | this.defaultHandler = handler;
73 | }
74 |
75 | private void init() {
76 | this.setVerticalScrollBarEnabled(false);
77 | this.setHorizontalScrollBarEnabled(false);
78 | this.getSettings().setJavaScriptEnabled(true);
79 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
80 | WebView.setWebContentsDebuggingEnabled(true);
81 | }
82 | this.setWebViewClient(generateBridgeWebViewClient());
83 | }
84 |
85 | protected BridgeWebViewClient generateBridgeWebViewClient() {
86 | return bridgeWebViewClient = new BridgeWebViewClient(this);
87 | }
88 |
89 | public void handlerReturnData(String url) {
90 | String functionName = BridgeUtil.getFunctionFromReturnUrl(url);
91 | CallBackFunction f = responseCallbacks.get(functionName);
92 | String data = BridgeUtil.getDataFromReturnUrl(url);
93 | if (f != null) {
94 | f.onCallBack(data);
95 | responseCallbacks.remove(functionName);
96 | return;
97 | }
98 | }
99 |
100 | @Override
101 | public void send(String data) {
102 | send(data, null);
103 | }
104 |
105 | @Override
106 | public void send(String data, CallBackFunction responseCallback) {
107 | doSend(null, data, responseCallback);
108 | }
109 |
110 | private void doSend(String handlerName, String data, CallBackFunction responseCallback) {
111 | Message m = new Message();
112 | if (!TextUtils.isEmpty(data)) {
113 | m.setData(data);
114 | }
115 | if (responseCallback != null) {
116 | String callbackStr = String.format(BridgeUtil.CALLBACK_ID_FORMAT, ++uniqueId + (BridgeUtil.UNDERLINE_STR + SystemClock.currentThreadTimeMillis()));
117 | responseCallbacks.put(callbackStr, responseCallback);
118 | m.setCallbackId(callbackStr);
119 | }
120 | if (!TextUtils.isEmpty(handlerName)) {
121 | m.setHandlerName(handlerName);
122 | }
123 | queueMessage(m);
124 | }
125 |
126 | private void queueMessage(Message m) {
127 | if (startupMessage != null) {
128 | startupMessage.add(m);
129 | } else {
130 | dispatchMessage(m);
131 | }
132 | }
133 |
134 | public void dispatchMessage(Message m) {
135 | String messageJson = m.toJson();
136 | //escape special characters for json string
137 | messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2");
138 | messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\"");
139 | String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA.replace(BridgeConfig.defaultJs, BridgeConfig.customJs), messageJson);
140 | if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
141 | this.loadUrl(javascriptCommand);
142 | }
143 | }
144 |
145 | public void flushMessageQueue() {
146 | if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
147 | loadUrl(BridgeUtil.JS_FETCH_QUEUE_FROM_JAVA.replace(BridgeConfig.defaultJs, BridgeConfig.customJs), new CallBackFunction() {
148 |
149 | @Override
150 | public void onCallBack(String data) {
151 | // deserializeMessage
152 | List list = null;
153 | try {
154 | list = Message.toArrayList(data);
155 | } catch (Exception e) {
156 | e.printStackTrace();
157 | return;
158 | }
159 | if (list == null || list.size() == 0) {
160 | return;
161 | }
162 | for (int i = 0; i < list.size(); i++) {
163 | Message m = list.get(i);
164 | String responseId = m.getResponseId();
165 | // 是否是response
166 | if (!TextUtils.isEmpty(responseId)) {
167 | CallBackFunction function = responseCallbacks.get(responseId);
168 | String responseData = m.getResponseData();
169 | function.onCallBack(responseData);
170 | responseCallbacks.remove(responseId);
171 | } else {
172 | CallBackFunction responseFunction = null;
173 | // if had callbackId
174 | final String callbackId = m.getCallbackId();
175 | if (!TextUtils.isEmpty(callbackId)) {
176 | responseFunction = new CallBackFunction() {
177 | @Override
178 | public void onCallBack(String data) {
179 | Message responseMsg = new Message();
180 | responseMsg.setResponseId(callbackId);
181 | responseMsg.setResponseData(data);
182 | queueMessage(responseMsg);
183 | }
184 | };
185 | } else {
186 | responseFunction = new CallBackFunction() {
187 | @Override
188 | public void onCallBack(String data) {
189 | // do nothing
190 | }
191 | };
192 | }
193 | BridgeHandler handler;
194 | if (!TextUtils.isEmpty(m.getHandlerName())) {
195 | handler = messageHandlers.get(m.getHandlerName());
196 | } else {
197 | handler = defaultHandler;
198 | }
199 | if (handler != null) {
200 | handler.handler(m.getData(), responseFunction);
201 | }
202 | }
203 | }
204 | }
205 | });
206 | }
207 | }
208 |
209 | public void loadUrl(String jsUrl, CallBackFunction returnCallback) {
210 | this.loadUrl(jsUrl);
211 | responseCallbacks.put(BridgeUtil.parseFunctionName(jsUrl, BridgeConfig.customJs), returnCallback);
212 | }
213 |
214 | /**
215 | * register handler,so that javascript can call it
216 | *
217 | * @param handlerName handlerName
218 | * @param handler Handler
219 | */
220 | public void registerHandler(String handlerName, BridgeHandler handler) {
221 | if (handler != null) {
222 | messageHandlers.put(handlerName, handler);
223 | }
224 | }
225 |
226 | /**
227 | * call javascript registered handler
228 | *
229 | * @param handlerName handlerName
230 | * @param data data
231 | * @param callBack callBack
232 | */
233 | public void callHandler(String handlerName, String data, CallBackFunction callBack) {
234 | doSend(handlerName, data, callBack);
235 | }
236 |
237 | public void setBridgeWebViewClientListener(BridgeWebViewClientListener bridgeWebViewClientListener) {
238 | bridgeWebViewClient.setBridgeWebViewClientListener(bridgeWebViewClientListener);
239 | }
240 |
241 | /**
242 | * 销毁时调用,移除listener
243 | */
244 | public void removeListener() {
245 | if (bridgeWebViewClient != null) {
246 | bridgeWebViewClient.removeListener();
247 | }
248 | if (onWebChromeClientListener != null) {
249 | onWebChromeClientListener = null;
250 | }
251 | }
252 |
253 | private OnWebChromeClientListener onWebChromeClientListener;
254 |
255 | public void setWebChromeClientListener(OnWebChromeClientListener onWebChromeClientListener) {
256 | this.onWebChromeClientListener = onWebChromeClientListener;
257 | setWebChromeClient(newWebChromeClient());
258 | }
259 |
260 | public void setWebChromeClientListener(WebChromeClientListener webChromeClientListener) {
261 | this.onWebChromeClientListener = webChromeClientListener;
262 | setWebChromeClient(newWebChromeClient());
263 | }
264 |
265 | private WebChromeClient newWebChromeClient() {
266 | WebChromeClient wvcc = new WebChromeClient() {
267 | @Override
268 | public void onExceededDatabaseQuota(String s, String s1, long l, long l1, long l2, WebStorage.QuotaUpdater quotaUpdater) {
269 | if (onWebChromeClientListener != null) {
270 | onWebChromeClientListener.onExceededDatabaseQuota(s, s1, l, l1, l2, quotaUpdater);
271 | } else {
272 | super.onExceededDatabaseQuota(s, s1, l, l1, l2, quotaUpdater);
273 | }
274 | }
275 |
276 | @Override
277 | public Bitmap getDefaultVideoPoster() {
278 | return onWebChromeClientListener != null ? onWebChromeClientListener.getDefaultVideoPoster() :
279 | super.getDefaultVideoPoster();
280 | }
281 |
282 | @Override
283 | public void getVisitedHistory(ValueCallback valueCallback) {
284 | if (onWebChromeClientListener != null) {
285 | onWebChromeClientListener.getVisitedHistory(valueCallback);
286 | } else {
287 | super.getVisitedHistory(valueCallback);
288 | }
289 | }
290 |
291 | @Override
292 | public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
293 | return onWebChromeClientListener != null ? onWebChromeClientListener.onConsoleMessage(consoleMessage) :
294 | super.onConsoleMessage(consoleMessage);
295 | }
296 |
297 | @Override
298 | public boolean onCreateWindow(WebView webView, boolean b, boolean b1, android.os.Message message) {
299 | return onWebChromeClientListener != null ? onWebChromeClientListener.onCreateWindow(webView, b, b1, message) :
300 | super.onCreateWindow(webView, b, b1, message);
301 | }
302 |
303 | @Override
304 | public void onGeolocationPermissionsHidePrompt() {
305 | if (onWebChromeClientListener != null) {
306 | onWebChromeClientListener.onGeolocationPermissionsHidePrompt();
307 | } else {
308 | super.onGeolocationPermissionsHidePrompt();
309 | }
310 | }
311 |
312 | @Override
313 | public void onGeolocationPermissionsShowPrompt(String s, GeolocationPermissionsCallback geolocationPermissionsCallback) {
314 | if (onWebChromeClientListener != null) {
315 | onWebChromeClientListener.onGeolocationPermissionsShowPrompt(s, geolocationPermissionsCallback);
316 | } else {
317 | super.onGeolocationPermissionsShowPrompt(s, geolocationPermissionsCallback);
318 | }
319 | }
320 |
321 | @Override
322 | public void onHideCustomView() {
323 | if (onWebChromeClientListener != null) {
324 | onWebChromeClientListener.onHideCustomView();
325 | } else {
326 | super.onHideCustomView();
327 | }
328 | }
329 |
330 | @Override
331 | public boolean onJsAlert(WebView webView, String s, String s1, JsResult jsResult) {
332 | return onWebChromeClientListener != null ? onWebChromeClientListener.onJsAlert(webView, s, s1, jsResult) :
333 | super.onJsAlert(webView, s, s1, jsResult);
334 | }
335 |
336 | @Override
337 | public boolean onJsConfirm(WebView webView, String s, String s1, JsResult jsResult) {
338 | return onWebChromeClientListener != null ? onWebChromeClientListener.onJsConfirm(webView, s, s1, jsResult) :
339 | super.onJsConfirm(webView, s, s1, jsResult);
340 | }
341 |
342 | @Override
343 | public boolean onJsPrompt(WebView webView, String s, String s1, String s2, JsPromptResult jsPromptResult) {
344 | return onWebChromeClientListener != null ? onWebChromeClientListener.onJsPrompt(webView, s, s1, s2, jsPromptResult) :
345 | super.onJsPrompt(webView, s, s1, s2, jsPromptResult);
346 | }
347 |
348 | @Override
349 | public boolean onJsBeforeUnload(WebView webView, String s, String s1, JsResult jsResult) {
350 | return onWebChromeClientListener != null ? onWebChromeClientListener.onJsBeforeUnload(webView, s, s1, jsResult) :
351 | super.onJsBeforeUnload(webView, s, s1, jsResult);
352 | }
353 |
354 | @Override
355 | public boolean onJsTimeout() {
356 | return onWebChromeClientListener != null ? onWebChromeClientListener.onJsTimeout() :
357 | super.onJsTimeout();
358 | }
359 |
360 | @Override
361 | public void onProgressChanged(WebView webView, int i) {
362 | if (onWebChromeClientListener != null) {
363 | onWebChromeClientListener.onProgressChanged(webView, i);
364 | } else {
365 | super.onProgressChanged(webView, i);
366 | }
367 | }
368 |
369 | @Override
370 | public void onReachedMaxAppCacheSize(long l, long l1, WebStorage.QuotaUpdater quotaUpdater) {
371 | if (onWebChromeClientListener != null) {
372 | onWebChromeClientListener.onReachedMaxAppCacheSize(l, l1, quotaUpdater);
373 | } else {
374 | super.onReachedMaxAppCacheSize(l, l1, quotaUpdater);
375 | }
376 | }
377 |
378 | @Override
379 | public void onReceivedIcon(WebView webView, Bitmap bitmap) {
380 | if (onWebChromeClientListener != null) {
381 | onWebChromeClientListener.onReceivedIcon(webView, bitmap);
382 | } else {
383 | super.onReceivedIcon(webView, bitmap);
384 | }
385 | }
386 |
387 | @Override
388 | public void onReceivedTouchIconUrl(WebView webView, String s, boolean b) {
389 | if (onWebChromeClientListener != null) {
390 | onWebChromeClientListener.onReceivedTouchIconUrl(webView, s, b);
391 | } else {
392 | super.onReceivedTouchIconUrl(webView, s, b);
393 | }
394 | }
395 |
396 | @Override
397 | public void onReceivedTitle(WebView webView, String s) {
398 | if (onWebChromeClientListener != null) {
399 | onWebChromeClientListener.onReceivedTitle(webView, s);
400 | } else {
401 | super.onReceivedTitle(webView, s);
402 | }
403 | }
404 |
405 | @Override
406 | public void onRequestFocus(WebView webView) {
407 | if (onWebChromeClientListener != null) {
408 | onWebChromeClientListener.onRequestFocus(webView);
409 | } else {
410 | super.onRequestFocus(webView);
411 | }
412 | }
413 |
414 | @Override
415 | public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback) {
416 | if (onWebChromeClientListener != null) {
417 | onWebChromeClientListener.onShowCustomView(view, customViewCallback);
418 | } else {
419 | super.onShowCustomView(view, customViewCallback);
420 | }
421 | }
422 |
423 | @Override
424 | public void onShowCustomView(View view, int i, IX5WebChromeClient.CustomViewCallback customViewCallback) {
425 | if (onWebChromeClientListener != null) {
426 | onWebChromeClientListener.onShowCustomView(view, i, customViewCallback);
427 | } else {
428 | super.onShowCustomView(view, i, customViewCallback);
429 | }
430 | }
431 |
432 | @Override
433 | public void onCloseWindow(WebView webView) {
434 | if (onWebChromeClientListener != null) {
435 | onWebChromeClientListener.onCloseWindow(webView);
436 | } else {
437 | super.onCloseWindow(webView);
438 | }
439 | }
440 |
441 | @Override
442 | public View getVideoLoadingProgressView() {
443 | return onWebChromeClientListener != null ? onWebChromeClientListener.getVideoLoadingProgressView() :
444 | super.getVideoLoadingProgressView();
445 | }
446 |
447 | @Override
448 | public void openFileChooser(ValueCallback valueCallback, String s, String s1) {
449 | if (onWebChromeClientListener != null) {
450 | onWebChromeClientListener.openFileChooser(valueCallback, s, s1);
451 | } else {
452 | super.openFileChooser(valueCallback, s, s1);
453 | }
454 | }
455 |
456 | @Override
457 | public boolean onShowFileChooser(WebView webView, ValueCallback valueCallback, FileChooserParams fileChooserParams) {
458 | return onWebChromeClientListener != null ? onWebChromeClientListener.onShowFileChooser(webView, valueCallback, fileChooserParams) :
459 | super.onShowFileChooser(webView, valueCallback, fileChooserParams);
460 | }
461 | };
462 | return wvcc;
463 | }
464 |
465 | /**
466 | * @param customJs 自定义桥名,可为空,为空时使用默认桥名
467 | * 自定义桥名回调,如用自定义桥名,请copy一份WebViewJavascriptBridge.js替换文件名
468 | * 及脚本内所有包含"WebViewJavascriptBridge"的内容为你的自定义桥名
469 | */
470 | public void setCustom(String customJs) {
471 | BridgeConfig.customJs = !TextUtils.isEmpty(customJs) ? customJs : BridgeConfig.defaultJs;
472 | }
473 | }
474 |
--------------------------------------------------------------------------------