├── .gitignore
├── README.md
├── X5EngineDemo.apk
├── X5WebEngineDemo
├── .gitignore
├── .idea
│ ├── compiler.xml
│ ├── copyright
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── runConfigurations.xml
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── libs
│ │ ├── armeabi
│ │ │ └── liblbs.so
│ │ └── tbs_sdk_thirdapp_v3.0.0.1038_43000_sharewithdownload_obfs_20170110_144724.jar
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── sunteng
│ │ │ └── x5webenginedemo
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ │ ├── test.zip
│ │ │ └── webpage
│ │ │ │ ├── Image.html
│ │ │ │ ├── SysJavaToJs.html
│ │ │ │ ├── clientnull.html
│ │ │ │ ├── cookieLost.html
│ │ │ │ ├── creat_new_window.html
│ │ │ │ ├── fileChooser.html
│ │ │ │ ├── firstX5.html
│ │ │ │ ├── fullscreenVideo.html
│ │ │ │ ├── hitTestResult.html
│ │ │ │ ├── image
│ │ │ │ ├── nearly.png
│ │ │ │ ├── scan.png
│ │ │ │ └── setting.png
│ │ │ │ ├── jsToJava.html
│ │ │ │ └── websocket.html
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── sunteng
│ │ │ │ └── x5webenginedemo
│ │ │ │ ├── AdvanceLoadX5Service.java
│ │ │ │ ├── Constant.java
│ │ │ │ ├── GameActivity.java
│ │ │ │ ├── JSToNativeActivity.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── NativeToJsActivity.java
│ │ │ │ ├── RefreshActivity.java
│ │ │ │ ├── Tool
│ │ │ │ ├── SecurityJsBridgeBundle.java
│ │ │ │ ├── WebViewJavaScriptFunction.java
│ │ │ │ ├── X5WebView.java
│ │ │ │ └── X5WebViewEventHandler.java
│ │ │ │ └── X5Application.java
│ │ ├── jniLibs
│ │ │ └── armeabi
│ │ │ │ └── liblbs.so
│ │ └── res
│ │ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_native_to_js.xml
│ │ │ ├── game_layout.xml
│ │ │ ├── native_js_activity.xml
│ │ │ └── refresh_layout.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-ldpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-w820dp
│ │ │ └── dimens.xml
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── sunteng
│ │ └── x5webenginedemo
│ │ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
└── X5浏览器内核调研报告.pdf
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.ap_
3 | # Files for the ART/Dalvik VM
4 | *.dex
5 |
6 | # Java class files
7 | *.class
8 |
9 | # Generated files
10 | bin/
11 | gen/
12 | out/
13 |
14 | *.DS_Store
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/workspace.xml
38 |
39 | # Keystore files
40 | *.jks
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # X5WebEngineDemo
2 | X5 webview demo
3 |
--------------------------------------------------------------------------------
/X5EngineDemo.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5EngineDemo.apk
--------------------------------------------------------------------------------
/X5WebEngineDemo/.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 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/.idea/misc.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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.1"
6 | defaultConfig {
7 | applicationId "com.sunteng.x5webenginedemo"
8 | minSdkVersion 14
9 | targetSdkVersion 20
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
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 | }
24 |
25 | dependencies {
26 | compile fileTree(include: ['*.jar'], dir: 'libs')
27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
28 | exclude group: 'com.android.support', module: 'support-annotations'
29 | })
30 | compile 'com.android.support:appcompat-v7:25.1.0'
31 | testCompile 'junit:junit:4.12'
32 | compile files('libs/tbs_sdk_thirdapp_v3.0.0.1038_43000_sharewithdownload_obfs_20170110_144724.jar')
33 | }
34 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/libs/armeabi/liblbs.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/libs/armeabi/liblbs.so
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/libs/tbs_sdk_thirdapp_v3.0.0.1038_43000_sharewithdownload_obfs_20170110_144724.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/libs/tbs_sdk_thirdapp_v3.0.0.1038_43000_sharewithdownload_obfs_20170110_144724.jar
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/baishixian/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/androidTest/java/com/sunteng/x5webenginedemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
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 | * Instrumentation 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("com.sunteng.x5webenginedemo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/test.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/assets/test.zip
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/Image.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 长按选择图片
8 |
24 |
25 |
26 |
27 |
28 |
34 | 长按上方图片
35 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/SysJavaToJs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/clientnull.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/cookieLost.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/creat_new_window.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | create new window use open
11 | blank无法打开新窗口(TBS2.0支持开启新窗口)
12 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/fileChooser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | file chooser
7 |
15 |
21 |
22 |
23 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/firstX5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 第一次启动webview就能加载X5内核
7 |
8 |
9 |
18 |
19 |
20 | 第一次启动webview就能加载X5内核
21 |
22 | 使用时请注意:1、我们并不能保证X5内核首次安装,首次100%加载;
2、QbSdk.preInit()只需要调用一次就可以完成X5webview的初始化,但是这样的操作需要耗费一定时间。
23 | 所以,你可以将X5初始化的操作放置在app初始化的过程中,以便于后期调用X5能够立即构建X5webview。
24 |
25 |
26 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/fullscreenVideo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
52 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/hitTestResult.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 请长按一下html元素
7 |
12 |
13 |
14 | 请长按一下html元素
15 | hello world!
16 |
17 | 
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/image/nearly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/assets/webpage/image/nearly.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/image/scan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/assets/webpage/image/scan.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/image/setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/assets/webpage/image/setting.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/jsToJava.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
24 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
扫描出的js bridge有:
38 |
39 |
40 |
41 |
42 |
43 |
113 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/assets/webpage/websocket.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | WebSocket 测试
9 |
10 |
11 |
12 |
34 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/AdvanceLoadX5Service.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.support.annotation.Nullable;
7 | import android.util.Log;
8 |
9 | import com.tencent.smtt.sdk.QbSdk;
10 | import com.tencent.smtt.sdk.TbsListener;
11 |
12 | /**
13 | * X5WebEngineDemo Created by baishixian on 2017/1/20.
14 | */
15 | public class AdvanceLoadX5Service extends Service {
16 |
17 | @Nullable
18 | @Override
19 | public IBinder onBind(Intent intent) {
20 | return null;
21 | }
22 |
23 | @Override
24 | public void onCreate() {
25 | super.onCreate();
26 | initX5();
27 | }
28 |
29 | private void initX5() {
30 | //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
31 | //TbsDownloader.needDownload(getApplicationContext(), false);
32 |
33 | QbSdk.PreInitCallback preInitCallback = new QbSdk.PreInitCallback() {
34 |
35 | @Override
36 | public void onViewInitFinished(boolean arg0) {
37 | // TODO Auto-generated method stub
38 | Log.e("AdvanceLoadX5Service", " onViewInitFinished is " + arg0);
39 | }
40 |
41 | @Override
42 | public void onCoreInitFinished() {
43 | // TODO Auto-generated method stub
44 | Log.e("AdvanceLoadX5Service", " onCoreInitFinished");
45 | }
46 | };
47 |
48 | QbSdk.setTbsListener(new TbsListener() {
49 | @Override
50 | public void onDownloadFinish(int i) {
51 | Log.d("AdvanceLoadX5Service","onDownloadFinish");
52 | }
53 |
54 | @Override
55 | public void onInstallFinish(int i) {
56 | Log.d("AdvanceLoadX5Service","onInstallFinish");
57 | }
58 |
59 | @Override
60 | public void onDownloadProgress(int i) {
61 | Log.d("AdvanceLoadX5Service","onDownloadProgress:"+i);
62 | }
63 | });
64 |
65 | QbSdk.initX5Environment(getApplicationContext(), preInitCallback);
66 |
67 | Log.d("AdvanceLoadX5Service","X5预加载中...");
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/Constant.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 | /**
4 | * X5WebEngineDemo Created by baishixian on 2017/1/20.
5 | */
6 |
7 | public interface Constant {
8 | String SYSTEM_WEBVIEW_TAG = "system_web";
9 | String X5_WEBVIEW_TAG = "X5_web";
10 | String WEBVIEW_ENGINE_TYPE = "webType";
11 | }
12 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/GameActivity.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.graphics.PixelFormat;
7 | import android.net.Uri;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.util.Log;
12 | import android.view.KeyEvent;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.Window;
16 | import android.view.WindowManager;
17 | import android.widget.FrameLayout;
18 | import android.widget.LinearLayout;
19 | import android.widget.Toast;
20 |
21 | import com.sunteng.x5webenginedemo.Tool.X5WebView;
22 | import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
23 | import com.tencent.smtt.export.external.interfaces.JsResult;
24 | import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
25 | import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
26 | import com.tencent.smtt.sdk.ValueCallback;
27 | import com.tencent.smtt.sdk.WebChromeClient;
28 | import com.tencent.smtt.sdk.WebSettings;
29 | import com.tencent.smtt.sdk.WebView;
30 | import com.tencent.smtt.sdk.WebViewClient;
31 |
32 | /**
33 | * X5WebEngineDemo Created by baishixian on 2017/1/20.
34 | */
35 | public class GameActivity extends AppCompatActivity {
36 | private static final String APP_NAME_UA = "Android_X5_CORE_WEB";
37 | private FrameLayout mViewParent;
38 | private WebView x5WebView;
39 | private android.webkit.WebView mSystemWebView;
40 | private ProgressDialog mProgressDialog;
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | this.requestWindowFeature(Window.FEATURE_NO_TITLE);
46 |
47 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
48 |
49 | getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
50 |
51 | // Set layout
52 | getWindow().setFormat(PixelFormat.TRANSLUCENT);
53 | setContentView(R.layout.game_layout);
54 | mViewParent = (FrameLayout)findViewById(R.id.game_parent);
55 |
56 | Intent intent = getIntent();
57 | if (intent != null){
58 | String webViewType = intent.getStringExtra(Constant.WEBVIEW_ENGINE_TYPE);
59 | if (webViewType.equals(Constant.X5_WEBVIEW_TAG)){
60 | initX5WebView();
61 | }else {
62 | initSystemWebView();
63 | }
64 | }
65 |
66 | showProgressBar();
67 | if (x5WebView != null){
68 | Toast.makeText(GameActivity.this, "正在使用X5内核运行H5游戏" , Toast.LENGTH_SHORT).show();
69 | x5WebView.loadUrl("http://developer.egret.com/cn/article/index/id/963");
70 | }else{
71 | Toast.makeText(GameActivity.this, "正在使用System内核运行H5游戏" , Toast.LENGTH_SHORT).show();
72 | mSystemWebView.loadUrl("http://developer.egret.com/cn/article/index/id/963");
73 | }
74 |
75 | /*Tbs视频播放器,页面H5视频播放
76 | public static boolean canUseTbsPlayer(Context context) //判断当前Tbs播放器是否已经可以使用。
77 | public static void openVideo(Context context, String videoUrl) //直接调用播放接口,传入视频流的url
78 | public static void openVideo(Context context, String videoUrl, Bundle extraData) //extraData对象是根据定制需要传入约定的信息,没有需要可以传如null
79 | */
80 |
81 | }
82 |
83 | private void initSystemWebView() {
84 | mSystemWebView = new android.webkit.WebView(GameActivity.this);
85 | mSystemWebView.setTag(Constant.SYSTEM_WEBVIEW_TAG);
86 | mViewParent.addView(mSystemWebView, new LinearLayout.LayoutParams(
87 | LinearLayout.LayoutParams.MATCH_PARENT,
88 | LinearLayout.LayoutParams.MATCH_PARENT));
89 |
90 | mSystemWebView.setWebViewClient(new android.webkit.WebViewClient() {
91 | @Override
92 | public boolean shouldOverrideUrlLoading(android.webkit.WebView view, String url) {
93 | return false;
94 | }
95 |
96 | @Override
97 | public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView view,
98 | android.webkit.WebResourceRequest request) {
99 | // TODO Auto-generated method stub
100 | return super.shouldInterceptRequest(view, request);
101 | }
102 |
103 |
104 |
105 | @Override
106 | public void onPageFinished(android.webkit.WebView view, String url) {
107 | super.onPageFinished(view, url);
108 | cancelProgressBar();
109 | }
110 | });
111 |
112 | initSystemWebViewSettings();
113 | }
114 |
115 | private void initX5WebView() {
116 | x5WebView = new X5WebView(GameActivity.this);
117 | x5WebView.setTag(Constant.X5_WEBVIEW_TAG);
118 | mViewParent.addView(x5WebView, new LinearLayout.LayoutParams(
119 | LinearLayout.LayoutParams.MATCH_PARENT,
120 | LinearLayout.LayoutParams.MATCH_PARENT));
121 |
122 | x5WebView.setWebViewClient(new WebViewClient() {
123 | @Override
124 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
125 | return false;
126 | }
127 |
128 | @Override
129 | public WebResourceResponse shouldInterceptRequest(WebView view,
130 | WebResourceRequest request) {
131 | // TODO Auto-generated method stub
132 |
133 | Log.e("should", "request.getUrl().toString() is " + request.getUrl().toString());
134 |
135 | return super.shouldInterceptRequest(view, request);
136 | }
137 |
138 |
139 |
140 | @Override
141 | public void onPageFinished(WebView view, String url) {
142 | super.onPageFinished(view, url);
143 | cancelProgressBar();
144 | }
145 | });
146 | x5WebView.setWebChromeClient(new WebChromeClient() {
147 |
148 | @Override
149 | public boolean onJsConfirm(WebView arg0, String arg1, String arg2, JsResult arg3) {
150 | return super.onJsConfirm(arg0, arg1, arg2, arg3);
151 | }
152 |
153 | View myVideoView;
154 | View myNormalView;
155 | IX5WebChromeClient.CustomViewCallback callback;
156 |
157 | ///////////////////////////////////////////////////////////
158 | //
159 | /**
160 | * 全屏播放配置
161 | */
162 | @Override
163 | public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback) {
164 | FrameLayout normalView = (FrameLayout) findViewById(R.id.web_filechooser);
165 | ViewGroup viewGroup = (ViewGroup) normalView.getParent();
166 | viewGroup.removeView(normalView);
167 | viewGroup.addView(view);
168 | myVideoView = view;
169 | myNormalView = normalView;
170 | callback = customViewCallback;
171 | }
172 |
173 | @Override
174 | public void onHideCustomView() {
175 | if (callback != null) {
176 | callback.onCustomViewHidden();
177 | callback = null;
178 | }
179 | if (myVideoView != null) {
180 | ViewGroup viewGroup = (ViewGroup) myVideoView.getParent();
181 | viewGroup.removeView(myVideoView);
182 | viewGroup.addView(myNormalView);
183 | }
184 | }
185 |
186 | @Override
187 | public boolean onShowFileChooser(WebView arg0,
188 | ValueCallback arg1, FileChooserParams arg2) {
189 | // TODO Auto-generated method stub
190 | Log.e("app", "onShowFileChooser");
191 | return super.onShowFileChooser(arg0, arg1, arg2);
192 | }
193 |
194 | @Override
195 | public void openFileChooser(ValueCallback uploadFile, String acceptType, String captureType) {
196 | }
197 |
198 |
199 | @Override
200 | public boolean onJsAlert(WebView arg0, String arg1, String arg2, JsResult arg3) {
201 | /**
202 | * 这里写入你自定义的window alert
203 | */
204 | Log.i("onReceivedTitle", "setX5webview = null");
205 | return super.onJsAlert(null, "www.baidu.com", "aa", arg3);
206 | }
207 |
208 | /**
209 | * 对应js 的通知弹框 ,可以用来实现js 和 android之间的通信
210 | */
211 |
212 |
213 | @Override
214 | public void onReceivedTitle(WebView arg0, final String arg1) {
215 | super.onReceivedTitle(arg0, arg1);
216 | Log.i("onReceivedTitle", "webpage title is " + arg1);
217 |
218 | }
219 | });
220 |
221 | initX5WebViewSettings();
222 | }
223 |
224 |
225 | private void showProgressBar() {
226 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
227 | mProgressDialog = new ProgressDialog(GameActivity.this, android.R.style.Theme_Material_Light_Dialog_Alert);
228 | } else {
229 | mProgressDialog = new ProgressDialog(GameActivity.this);
230 | }
231 | mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
232 | mProgressDialog.setTitle("游戏加载中,请稍后");
233 | mProgressDialog.show();
234 | }
235 |
236 |
237 | private void cancelProgressBar() {
238 | if (mProgressDialog != null && mProgressDialog.isShowing()){
239 | mProgressDialog.cancel();
240 | }
241 | }
242 |
243 | private void initX5WebViewSettings() {
244 | WebSettings webSetting = x5WebView.getSettings();
245 | webSetting.setJavaScriptEnabled(true);
246 | webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
247 | webSetting.setAllowFileAccess(true);
248 | webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
249 | webSetting.setSupportZoom(true);
250 | webSetting.setBuiltInZoomControls(true);
251 | webSetting.setUseWideViewPort(true);
252 | webSetting.setSupportMultipleWindows(true);
253 | //webSetting.setLoadWithOverviewMode(true);
254 | webSetting.setAppCacheEnabled(true);
255 | //webSetting.setDatabaseEnabled(true);
256 | webSetting.setDomStorageEnabled(true);
257 | webSetting.setGeolocationEnabled(true);
258 | webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
259 | // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
260 | webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
261 | //webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
262 | webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);
263 |
264 | // this.getSettingsExtension().setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);//extension
265 | // settings 的设计
266 | }
267 |
268 | private void initSystemWebViewSettings() {
269 | android.webkit.WebSettings webSetting = mSystemWebView.getSettings();
270 | webSetting.setJavaScriptEnabled(true);
271 | webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
272 | webSetting.setAllowFileAccess(true);
273 | webSetting.setLayoutAlgorithm(android.webkit.WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
274 | webSetting.setSupportZoom(true);
275 | webSetting.setBuiltInZoomControls(true);
276 | webSetting.setUseWideViewPort(true);
277 | webSetting.setSupportMultipleWindows(true);
278 | //webSetting.setLoadWithOverviewMode(true);
279 | webSetting.setAppCacheEnabled(true);
280 | //webSetting.setDatabaseEnabled(true);
281 | webSetting.setDomStorageEnabled(true);
282 | webSetting.setGeolocationEnabled(true);
283 | webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
284 | // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
285 | webSetting.setPluginState(android.webkit.WebSettings.PluginState.ON_DEMAND);
286 | //webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
287 | webSetting.setCacheMode(android.webkit.WebSettings.LOAD_NO_CACHE);
288 |
289 | // this.getSettingsExtension().setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);//extension
290 | // settings 的设计
291 | }
292 |
293 | @Override
294 | protected void onResume() {
295 | super.onResume();
296 | }
297 |
298 | @Override
299 | public boolean onKeyDown(int keyCode, KeyEvent event) {
300 | if (keyCode == KeyEvent.KEYCODE_BACK) {
301 | if (x5WebView != null && x5WebView.canGoBack()){
302 | x5WebView.goBack();// 返回前一个页面
303 | return true;
304 | }else if (mSystemWebView != null && mSystemWebView.canGoBack()){
305 | mSystemWebView.goBack();// 返回前一个页面
306 | return true;
307 | }
308 | }
309 | return super.onKeyDown(keyCode, event);
310 | }
311 |
312 | @Override
313 | public void onBackPressed() {
314 | android.support.v7.app.AlertDialog.Builder builder;
315 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
316 | builder = new android.support.v7.app.AlertDialog.Builder(GameActivity.this, android.R.style.Theme_Material_Light_Dialog_Alert);
317 | } else {
318 | builder = new android.support.v7.app.AlertDialog.Builder(GameActivity.this);
319 | }
320 | builder.setIcon(R.mipmap.ic_launcher).setTitle("提示").setMessage("是否退出当前游戏界面?").setNegativeButton("否", new DialogInterface.OnClickListener() {
321 | @Override
322 | public void onClick(DialogInterface dialogInterface, int i) {
323 | dialogInterface.dismiss();
324 | }
325 | }).setPositiveButton("是", new DialogInterface.OnClickListener() {
326 | @Override
327 | public void onClick(DialogInterface dialogInterface, int i) {
328 | finish();
329 | }
330 | }).create().show();
331 | }
332 | }
333 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/JSToNativeActivity.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import android.os.Message;
8 | import android.util.Log;
9 | import android.view.View;
10 | import android.webkit.JavascriptInterface;
11 | import android.widget.EditText;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.sunteng.x5webenginedemo.Tool.WebViewJavaScriptFunction;
16 | import com.sunteng.x5webenginedemo.Tool.X5WebView;
17 |
18 | /**
19 | * X5WebEngineDemo Created by baishixian on 2017/1/20.
20 | */
21 |
22 | public class JSToNativeActivity extends Activity implements View.OnClickListener {
23 |
24 | private EditText nativeToJsEdit;
25 | private TextView nativeToJsNumTextView;
26 |
27 |
28 | private Handler handler;
29 |
30 | private static final int MSG=0;
31 | private static final int NUM=1;
32 | private static final int MSG_SUBMIT=2;
33 | private static final int CLOSE_SUBMIT=3;
34 |
35 | private int num=0;
36 | private String msg="X5 WebView";
37 |
38 | private X5WebView mWebView;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.native_js_activity);
44 |
45 |
46 | this.handler=new Handler(Looper.myLooper()){
47 |
48 | @Override
49 | public void handleMessage(Message msg) {
50 | // TODO Auto-generated method stub
51 | switch(msg.what){
52 | case NUM:
53 | JSToNativeActivity.this.nativeToJsNumTextView.setText(String.valueOf(num));
54 | break;
55 | case MSG:
56 | JSToNativeActivity.this.nativeToJsEdit.setText(JSToNativeActivity.this.msg);
57 | break;
58 | case MSG_SUBMIT:
59 | JSToNativeActivity.this.msg = JSToNativeActivity.this.nativeToJsEdit.getEditableText().toString();
60 | break;
61 | case CLOSE_SUBMIT:
62 | Toast.makeText(JSToNativeActivity.this.getApplicationContext() , "Js 异步触发 Android 窗口关闭事件", Toast.LENGTH_SHORT).show();
63 | break;
64 | }
65 | super.handleMessage(msg);
66 |
67 | }
68 |
69 | };
70 |
71 | initView();
72 |
73 | mWebView.loadUrl("file:///android_asset/webpage/jsToJava.html");
74 |
75 | mWebView.addJavascriptInterface(new WebViewJavaScriptFunction() {
76 |
77 | @Override
78 | public void onJsFunctionCalled(String tag) {
79 | // TODO Auto-generated method stub
80 | Log.i("jsToAndroid","onJsFunctionCalled tag : " + tag);
81 | }
82 | ///////////////////////////////////////////////
83 | //javascript to java methods
84 | @JavascriptInterface
85 | public void onSubmit(String s){
86 | Log.i("jsToAndroid","onSubmit happend! " + s);
87 | JSToNativeActivity.this.msg = s;
88 | Message.obtain(handler, MSG).sendToTarget();
89 | }
90 |
91 | @JavascriptInterface
92 | public void onSubmitNum(String s){
93 | Log.i("jsToAndroid","onSubmitNum happend! " + s);
94 | JSToNativeActivity.this.num = Integer.parseInt(s);
95 | Message.obtain(handler, NUM).sendToTarget();
96 | }
97 |
98 |
99 | /**
100 | * java 调用 js方法 并且 传值
101 | * 步骤:1、调用 js函数 2、js回调一个android方法得到参数 3、js处理函数
102 | * @return
103 | */
104 | @JavascriptInterface
105 | public String getAndroidMsg(){
106 | Log.i("jsToAndroid","onSubmitNum happend!");
107 | return JSToNativeActivity.this.msg;
108 | }
109 |
110 | @JavascriptInterface
111 | public String getAndroidNum(){
112 | Log.i("jsToAndroid","onSubmitNum happend!");
113 | return String.valueOf(JSToNativeActivity.this.num);
114 | }
115 |
116 |
117 |
118 | /**
119 | * 各种类型的传递
120 | */
121 | @JavascriptInterface
122 | public void getManyValue(String key,String value){
123 |
124 | Log.i("jsToAndroid", "get key is:"+key+" value is:"+value);
125 | }
126 |
127 | /**
128 | * 关闭当前的窗口
129 | */
130 | @JavascriptInterface
131 | public void closeCurrentWindow(){
132 | Message.obtain(handler, NUM).sendToTarget();
133 | JSToNativeActivity.this.finish();
134 | }
135 | }, "Android");
136 | }
137 |
138 | private void initView() {
139 |
140 | nativeToJsEdit = (EditText)findViewById(R.id.edit_native_js_edit);
141 | this.nativeToJsEdit.setHint("请输入与js交互并web上展示的内容");
142 |
143 | nativeToJsNumTextView = (TextView)findViewById(R.id.text_native_js_num);
144 | this.nativeToJsNumTextView.setText("" + this.num);
145 |
146 | mWebView = (X5WebView) findViewById(R.id.x5web_native2js);
147 |
148 | findViewById(R.id.bt_native_js_edit).setOnClickListener(this);
149 | findViewById(R.id.bt_native_js_num_add).setOnClickListener(this);
150 | findViewById(R.id.bt_native_js_num_minuse).setOnClickListener(this);
151 | findViewById(R.id.web_native_js_close_btn).setOnClickListener(this);
152 | }
153 |
154 | @Override
155 | public void onClick(View v) {
156 |
157 | int num = Integer.parseInt(JSToNativeActivity.this.nativeToJsNumTextView.getText().toString());
158 |
159 | switch (v.getId()){
160 | case R.id.bt_native_js_edit:
161 | Message.obtain(handler, MSG_SUBMIT).sendToTarget();
162 | JSToNativeActivity.this.mWebView.loadUrl("javascript:returnMsg()");
163 | break;
164 | case R.id.web_native_js_close_btn:
165 | Message.obtain(handler, CLOSE_SUBMIT).sendToTarget();
166 | JSToNativeActivity.this.mWebView.loadUrl("javascript:closeWnd()");
167 | break;
168 | case R.id.bt_native_js_num_add:
169 | JSToNativeActivity.this.num++;
170 | JSToNativeActivity.this.num=(++num);
171 | Message.obtain(handler, NUM).sendToTarget();
172 | JSToNativeActivity.this.mWebView.loadUrl("javascript:returnNum()");
173 | break;
174 | case R.id.bt_native_js_num_minuse:
175 | JSToNativeActivity.this.num=(--num);
176 | JSToNativeActivity.this.mWebView.loadUrl("javascript:returnNum()");
177 | break;
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.net.Uri;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.support.v7.app.AlertDialog;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.support.v7.widget.SearchView;
13 | import android.support.v7.widget.Toolbar;
14 | import android.util.Log;
15 | import android.view.KeyEvent;
16 | import android.view.View;
17 | import android.view.ViewGroup;
18 | import android.view.inputmethod.InputMethodManager;
19 | import android.widget.CompoundButton;
20 | import android.widget.FrameLayout;
21 | import android.widget.LinearLayout;
22 | import android.widget.TextView;
23 | import android.widget.Toast;
24 | import android.widget.ToggleButton;
25 |
26 | import com.sunteng.x5webenginedemo.Tool.X5WebView;
27 | import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
28 | import com.tencent.smtt.export.external.interfaces.JsResult;
29 | import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
30 | import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
31 | import com.tencent.smtt.sdk.CookieSyncManager;
32 | import com.tencent.smtt.sdk.DownloadListener;
33 | import com.tencent.smtt.sdk.ValueCallback;
34 | import com.tencent.smtt.sdk.WebChromeClient;
35 | import com.tencent.smtt.sdk.WebSettings;
36 | import com.tencent.smtt.sdk.WebView;
37 | import com.tencent.smtt.sdk.WebViewClient;
38 | import com.tencent.smtt.utils.TbsLog;
39 |
40 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
41 |
42 | private SearchView mSearchBar;
43 | private Toolbar mToolbar;
44 | private LinearLayout mParentView;
45 | private ValueCallback uploadFile;
46 | private ProgressDialog mProgressDialog;
47 |
48 | private X5WebView x5WebView;
49 | private android.webkit.WebView mSystemWebView;
50 |
51 | private FrameLayout mWebController;
52 | private ToggleButton mChangeEngine;
53 | private boolean isEnableX5Engine = false;
54 | private TextView mHintShowInfoText;
55 | private long time = 0;
56 | private LinearLayout idel_layout;
57 |
58 | @Override
59 | protected void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setContentView(R.layout.activity_main);
62 | initView();
63 | }
64 |
65 | private void initView(){
66 |
67 | mToolbar = (Toolbar) findViewById(R.id.toolbar);
68 |
69 | setSupportActionBar(mToolbar);
70 | mToolbar.setOnClickListener(this);
71 |
72 | android.support.v7.app.ActionBar actionBar = getSupportActionBar();
73 | if (actionBar != null) {
74 | actionBar.setDisplayHomeAsUpEnabled(true);
75 | }
76 |
77 | mSearchBar = (SearchView) findViewById(R.id.search_bar);
78 | mSearchBar.setQueryHint("输入网址");
79 | mSearchBar.setOnQueryTextListener(onQueryTextListener);
80 |
81 | mParentView = (LinearLayout)findViewById(R.id.web_parent);
82 |
83 | mHintShowInfoText = (TextView)findViewById(R.id.tv_show_info);
84 |
85 | mWebController = (FrameLayout)findViewById(R.id.web_controller);
86 |
87 | mChangeEngine = (ToggleButton)findViewById(R.id.web_control_change_engine);
88 | mChangeEngine.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
89 | @Override
90 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
91 | changeWebViewEngine(isChecked);
92 | }
93 | });
94 |
95 | findViewById(R.id.web_control_start_game).setOnClickListener(this);
96 | findViewById(R.id.web_control_js_native).setOnClickListener(this);
97 | findViewById(R.id.web_control_exit).setOnClickListener(this);
98 |
99 | findViewById(R.id.bt_show_qq_video).setOnClickListener(this);
100 | findViewById(R.id.bt_show_bilibili_video).setOnClickListener(this);
101 |
102 | idel_layout = (LinearLayout)findViewById(R.id.idel_layout);
103 |
104 | }
105 |
106 | private void changeWebViewEngine(boolean isChecked) {
107 |
108 | isEnableX5Engine = isChecked;
109 |
110 | if (isChecked){
111 | Toast.makeText(MainActivity.this, "切换到X5内核", Toast.LENGTH_SHORT).show();
112 | }else {
113 | Toast.makeText(MainActivity.this, "切换到系统内核", Toast.LENGTH_SHORT).show();
114 | }
115 | }
116 |
117 | SearchView.OnQueryTextListener onQueryTextListener = new SearchView.OnQueryTextListener() {
118 | @Override
119 | public boolean onQueryTextSubmit(String query) {
120 |
121 | String openUrl;
122 |
123 | if (query.startsWith("http://") || query.startsWith("https://") || query.startsWith("ftp://")){
124 | openUrl = query;
125 | }else{
126 | openUrl = "http://" + query;
127 | }
128 |
129 | mSearchBar.clearFocus();
130 |
131 | if (idel_layout != null && mParentView.findViewById(R.id.idel_layout) != null){
132 | mParentView.removeView(idel_layout);
133 | }
134 |
135 | if (isEnableX5Engine){
136 | openWebUrlByX5(openUrl);
137 | }else {
138 | openWebUrlBySystem(openUrl);
139 | }
140 | return true;
141 | }
142 |
143 | @Override
144 | public boolean onQueryTextChange(String newText) {
145 | return false;
146 | }
147 | };
148 |
149 | private void openWebUrlBySystem(String openUrl) {
150 |
151 | showProgressBar();
152 |
153 | if (x5WebView != null && mParentView.findViewWithTag(Constant.X5_WEBVIEW_TAG) != null){
154 | Toast.makeText(MainActivity.this, "切换到了system浏览器内核,页面加载中", Toast.LENGTH_SHORT).show();
155 | mParentView.removeView(x5WebView);
156 | }
157 |
158 | if (mSystemWebView == null){
159 | intSystemWebView();
160 | }
161 |
162 | if (mParentView.findViewWithTag(Constant.SYSTEM_WEBVIEW_TAG) == null){
163 | mParentView.addView(mSystemWebView, new LinearLayout.LayoutParams(
164 | LinearLayout.LayoutParams.MATCH_PARENT,
165 | LinearLayout.LayoutParams.MATCH_PARENT));
166 | }
167 |
168 | time = System.currentTimeMillis();
169 | mSystemWebView.loadUrl(openUrl);
170 | CookieSyncManager.getInstance().sync();
171 | }
172 |
173 | private void intSystemWebView() {
174 | mSystemWebView = new android.webkit.WebView(MainActivity.this);
175 | mSystemWebView.setTag(Constant.SYSTEM_WEBVIEW_TAG);
176 | mParentView.addView(mSystemWebView, new LinearLayout.LayoutParams(
177 | LinearLayout.LayoutParams.MATCH_PARENT,
178 | LinearLayout.LayoutParams.MATCH_PARENT));
179 |
180 | mSystemWebView.setWebViewClient(new android.webkit.WebViewClient() {
181 | @Override
182 | public boolean shouldOverrideUrlLoading(android.webkit.WebView view, String url) {
183 | return false;
184 | }
185 |
186 | @Override
187 | public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView view,
188 | android.webkit.WebResourceRequest request) {
189 | // TODO Auto-generated method stub
190 | return super.shouldInterceptRequest(view, request);
191 | }
192 |
193 |
194 |
195 | @Override
196 | public void onPageFinished(android.webkit.WebView view, String url) {
197 | super.onPageFinished(view, url);
198 | long costTime = System.currentTimeMillis() - time;
199 | TbsLog.d("time-cost", "openWebUrlBySystem cost time: "
200 | + costTime);
201 | cancelProgressBar();
202 | Toast.makeText(MainActivity.this, "system浏览器内核加载 \n" + url + " \n耗时:" + costTime, Toast.LENGTH_SHORT).show();
203 | }
204 | });
205 |
206 | mSystemWebView.setDownloadListener(new android.webkit.DownloadListener() {
207 |
208 | @Override
209 | public void onDownloadStart(String arg0, String arg1, String arg2,
210 | String arg3, long arg4) {
211 | AlertDialog.Builder builder;
212 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
213 | builder = new AlertDialog.Builder(MainActivity.this, android.R.style.Theme_Material_Light_Dialog_Alert);
214 | } else {
215 | builder = new AlertDialog.Builder(MainActivity.this);
216 | }
217 | builder.setIcon(R.mipmap.ic_launcher).setTitle("是否下载文件")
218 | .setPositiveButton("yes",
219 | new DialogInterface.OnClickListener() {
220 |
221 | @Override
222 | public void onClick(DialogInterface dialog,
223 | int which) {
224 | Toast.makeText(
225 | MainActivity.this,
226 | "I'll download...",
227 | Toast.LENGTH_SHORT).show();
228 | }
229 | })
230 | .setNegativeButton("no",
231 | new DialogInterface.OnClickListener() {
232 |
233 | @Override
234 | public void onClick(DialogInterface dialog,
235 | int which) {
236 | // TODO Auto-generated method stub
237 | Toast.makeText(
238 | MainActivity.this,
239 | "no refuse download...",
240 | Toast.LENGTH_SHORT).show();
241 | }
242 | })
243 | .setOnCancelListener(
244 | new DialogInterface.OnCancelListener() {
245 |
246 | @Override
247 | public void onCancel(DialogInterface dialog) {
248 | // TODO Auto-generated method stub
249 | Toast.makeText(
250 | MainActivity.this,
251 | "refuse download...",
252 | Toast.LENGTH_SHORT).show();
253 | }
254 | }).show();
255 | }
256 | });
257 |
258 |
259 | android.webkit.WebSettings webSetting = mSystemWebView.getSettings();
260 | webSetting.setAllowFileAccess(true);
261 | webSetting.setLayoutAlgorithm( android.webkit.WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
262 | webSetting.setSupportZoom(true);
263 | webSetting.setBuiltInZoomControls(true);
264 | webSetting.setUseWideViewPort(true);
265 | webSetting.setSupportMultipleWindows(false);
266 | //webSetting.setLoadWithOverviewMode(true);
267 | webSetting.setAppCacheEnabled(true);
268 | //webSetting.setDatabaseEnabled(true);
269 | webSetting.setDomStorageEnabled(true);
270 | webSetting.setJavaScriptEnabled(true);
271 | webSetting.setGeolocationEnabled(true);
272 | webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
273 | webSetting.setAppCachePath(this.getDir("appcache", 0).getPath());
274 | webSetting.setDatabasePath(this.getDir("databases", 0).getPath());
275 | webSetting.setGeolocationDatabasePath(this.getDir("geolocation", 0)
276 | .getPath());
277 | // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
278 | webSetting.setPluginState( android.webkit.WebSettings.PluginState.ON_DEMAND);
279 | //webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
280 | // webSetting.setPreFectch(true);
281 |
282 | CookieSyncManager.createInstance(this);
283 | }
284 |
285 | private void openWebUrlByX5(String url) {
286 |
287 | showProgressBar();
288 |
289 | if (mSystemWebView != null && mParentView.findViewWithTag(Constant.SYSTEM_WEBVIEW_TAG) != null){
290 | Toast.makeText(MainActivity.this, "切换到了X5浏览器内核,页面加载中", Toast.LENGTH_SHORT).show();
291 | mParentView.removeView(mSystemWebView);
292 | }
293 |
294 | if (x5WebView == null){
295 | initX5WebView();
296 | }
297 |
298 | if (mParentView.findViewWithTag(Constant.X5_WEBVIEW_TAG) == null){
299 | mParentView.addView(x5WebView, new LinearLayout.LayoutParams(
300 | LinearLayout.LayoutParams.MATCH_PARENT,
301 | LinearLayout.LayoutParams.MATCH_PARENT));
302 | }
303 |
304 | time = System.currentTimeMillis();
305 | x5WebView.loadUrl(url);
306 | CookieSyncManager.getInstance().sync();
307 | }
308 |
309 | private void initX5WebView() {
310 | x5WebView = new X5WebView(MainActivity.this);
311 | x5WebView.setTag(Constant.X5_WEBVIEW_TAG);
312 | mParentView.addView(x5WebView, new LinearLayout.LayoutParams(
313 | LinearLayout.LayoutParams.MATCH_PARENT,
314 | LinearLayout.LayoutParams.MATCH_PARENT));
315 |
316 | x5WebView.setWebViewClient(new WebViewClient() {
317 | @Override
318 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
319 | return false;
320 | }
321 |
322 | @Override
323 | public WebResourceResponse shouldInterceptRequest(WebView view,
324 | WebResourceRequest request) {
325 | // TODO Auto-generated method stub
326 |
327 | Log.e("should", "request.getUrl().toString() is " + request.getUrl().toString());
328 |
329 | return super.shouldInterceptRequest(view, request);
330 | }
331 |
332 |
333 |
334 | @Override
335 | public void onPageFinished(WebView view, String url) {
336 | super.onPageFinished(view, url);
337 | long costTime = System.currentTimeMillis() - time;
338 | TbsLog.d("time-cost", "openWebUrlByX5 cost time: "
339 | + costTime);
340 | cancelProgressBar();
341 | Toast.makeText(MainActivity.this, "X5内核加载 \n" + url + " \n耗时:" + costTime, Toast.LENGTH_SHORT).show();
342 | }
343 | });
344 |
345 | x5WebView.setWebChromeClient(new WebChromeClient() {
346 |
347 | @Override
348 | public boolean onJsConfirm(WebView arg0, String arg1, String arg2, JsResult arg3) {
349 | return super.onJsConfirm(arg0, arg1, arg2, arg3);
350 | }
351 |
352 | View myVideoView;
353 | View myNormalView;
354 | IX5WebChromeClient.CustomViewCallback callback;
355 |
356 | ///////////////////////////////////////////////////////////
357 | //
358 | /**
359 | * 全屏播放配置
360 | */
361 | @Override
362 | public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback) {
363 | FrameLayout normalView = (FrameLayout) findViewById(R.id.web_filechooser);
364 | ViewGroup viewGroup = (ViewGroup) normalView.getParent();
365 | viewGroup.removeView(normalView);
366 | viewGroup.addView(view);
367 | myVideoView = view;
368 | myNormalView = normalView;
369 | callback = customViewCallback;
370 | }
371 |
372 | @Override
373 | public void onHideCustomView() {
374 | if (callback != null) {
375 | callback.onCustomViewHidden();
376 | callback = null;
377 | }
378 | if (myVideoView != null) {
379 | ViewGroup viewGroup = (ViewGroup) myVideoView.getParent();
380 | viewGroup.removeView(myVideoView);
381 | viewGroup.addView(myNormalView);
382 | }
383 | }
384 |
385 | @Override
386 | public boolean onShowFileChooser(WebView arg0,
387 | ValueCallback arg1, FileChooserParams arg2) {
388 | // TODO Auto-generated method stub
389 | Log.e("app", "onShowFileChooser");
390 | return super.onShowFileChooser(arg0, arg1, arg2);
391 | }
392 |
393 | @Override
394 | public void openFileChooser(ValueCallback uploadFile, String acceptType, String captureType) {
395 | MainActivity.this.uploadFile = uploadFile;
396 | Intent i = new Intent(Intent.ACTION_GET_CONTENT);
397 | i.addCategory(Intent.CATEGORY_OPENABLE);
398 | i.setType("*/*");
399 | startActivityForResult(Intent.createChooser(i, "test"), 0);
400 | }
401 |
402 |
403 | @Override
404 | public boolean onJsAlert(WebView arg0, String arg1, String arg2, JsResult arg3) {
405 | /**
406 | * 这里写入你自定义的window alert
407 | */
408 | // AlertDialog.Builder builder = new Builder(getContext());
409 | // builder.setTitle("X5内核");
410 | // builder.setPositiveButton("确定", new
411 | // DialogInterface.OnClickListener() {
412 | //
413 | // @Override
414 | // public void onClick(DialogInterface dialog, int which) {
415 | // // TODO Auto-generated method stub
416 | // dialog.dismiss();
417 | // }
418 | // });
419 | // builder.show();
420 | // arg3.confirm();
421 | // return true;
422 | Log.i("onReceivedTitle", "setX5webview = null");
423 | return super.onJsAlert(null, "www.baidu.com", "aa", arg3);
424 | }
425 |
426 | /**
427 | * 对应js 的通知弹框 ,可以用来实现js 和 android之间的通信
428 | */
429 |
430 |
431 | @Override
432 | public void onReceivedTitle(WebView arg0, final String arg1) {
433 | super.onReceivedTitle(arg0, arg1);
434 | Log.i("onReceivedTitle", "webpage title is " + arg1);
435 |
436 | }
437 | });
438 |
439 | x5WebView.setDownloadListener(new DownloadListener() {
440 |
441 | @Override
442 | public void onDownloadStart(String arg0, String arg1, String arg2,
443 | String arg3, long arg4) {
444 |
445 | AlertDialog.Builder builder;
446 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
447 | builder = new AlertDialog.Builder(MainActivity.this, android.R.style.Theme_Material_Light_Dialog_Alert);
448 | } else {
449 | builder = new AlertDialog.Builder(MainActivity.this);
450 | }
451 |
452 | builder.setIcon(R.mipmap.ic_launcher).setTitle("是否下载文件")
453 | .setPositiveButton("yes",
454 | new DialogInterface.OnClickListener() {
455 |
456 | @Override
457 | public void onClick(DialogInterface dialog,
458 | int which) {
459 | Toast.makeText(
460 | MainActivity.this,
461 | "I'll download...",
462 | Toast.LENGTH_SHORT).show();
463 | }
464 | })
465 | .setNegativeButton("no",
466 | new DialogInterface.OnClickListener() {
467 |
468 | @Override
469 | public void onClick(DialogInterface dialog,
470 | int which) {
471 | // TODO Auto-generated method stub
472 | Toast.makeText(
473 | MainActivity.this,
474 | "no refuse download...",
475 | Toast.LENGTH_SHORT).show();
476 | }
477 | })
478 | .setOnCancelListener(
479 | new DialogInterface.OnCancelListener() {
480 |
481 | @Override
482 | public void onCancel(DialogInterface dialog) {
483 | // TODO Auto-generated method stub
484 | Toast.makeText(
485 | MainActivity.this,
486 | "refuse download...",
487 | Toast.LENGTH_SHORT).show();
488 | }
489 | }).show();
490 | }
491 | });
492 |
493 |
494 | WebSettings webSetting = x5WebView.getSettings();
495 | webSetting.setAllowFileAccess(true);
496 | webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
497 | webSetting.setSupportZoom(true);
498 | webSetting.setBuiltInZoomControls(true);
499 | webSetting.setUseWideViewPort(true);
500 | webSetting.setSupportMultipleWindows(false);
501 | //webSetting.setLoadWithOverviewMode(true);
502 | webSetting.setAppCacheEnabled(true);
503 | //webSetting.setDatabaseEnabled(true);
504 | webSetting.setDomStorageEnabled(true);
505 | webSetting.setJavaScriptEnabled(true);
506 | webSetting.setGeolocationEnabled(true);
507 | webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
508 | webSetting.setAppCachePath(this.getDir("appcache", 0).getPath());
509 | webSetting.setDatabasePath(this.getDir("databases", 0).getPath());
510 | webSetting.setGeolocationDatabasePath(this.getDir("geolocation", 0)
511 | .getPath());
512 | // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
513 | webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
514 | //webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
515 | // webSetting.setPreFectch(true);
516 |
517 | CookieSyncManager.createInstance(this);
518 | }
519 |
520 |
521 | public void hideSoftInputKeyBoard(){
522 | ((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
523 | }
524 |
525 | private void showProgressBar() {
526 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
527 | mProgressDialog = new ProgressDialog(MainActivity.this, android.R.style.Theme_Material_Light_Dialog_Alert);
528 | } else {
529 | mProgressDialog = new ProgressDialog(MainActivity.this);
530 | }
531 | mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
532 | mProgressDialog.setTitle("页面加载中,请稍后");
533 | mProgressDialog.show();
534 | }
535 |
536 |
537 | private void cancelProgressBar() {
538 | if (mProgressDialog != null && mProgressDialog.isShowing()){
539 | mProgressDialog.cancel();
540 | }
541 | }
542 |
543 |
544 | @Override
545 | public void onClick(View v) {
546 | switch (v.getId()){
547 | case R.id.toolbar:
548 | mSearchBar.setIconified(false);
549 | break;
550 | case R.id.web_control_start_game:
551 | Intent intent = new Intent(MainActivity.this, GameActivity.class);
552 | if (isEnableX5Engine){
553 | intent.putExtra(Constant.WEBVIEW_ENGINE_TYPE, Constant.X5_WEBVIEW_TAG);
554 | }else{
555 | intent.putExtra(Constant.WEBVIEW_ENGINE_TYPE, Constant.SYSTEM_WEBVIEW_TAG);
556 | }
557 | startActivity(intent);
558 | break;
559 | case R.id.web_control_js_native:
560 | startActivity(new Intent(MainActivity.this, NativeToJsActivity.class));
561 | break;
562 | case R.id.web_control_exit:
563 | System.exit(0);
564 | break;
565 | case R.id.bt_show_qq_video:
566 | if (idel_layout != null && mParentView.findViewById(R.id.idel_layout) != null){
567 | mParentView.removeView(idel_layout);
568 | }
569 | if (isEnableX5Engine){
570 | openWebUrlByX5("https://v.qq.com");
571 | }else{
572 | openWebUrlBySystem("https://v.qq.com");
573 | }
574 | break;
575 | case R.id.bt_show_bilibili_video:
576 | if (idel_layout != null && mParentView.findViewById(R.id.idel_layout) != null){
577 | mParentView.removeView(idel_layout);
578 | }
579 | if (isEnableX5Engine){
580 | openWebUrlByX5("http://www.bilibili.com");
581 | }else{
582 | openWebUrlBySystem("http://www.bilibili.com");
583 | }
584 | break;
585 | default:break;
586 | }
587 | }
588 |
589 | @Override
590 | public boolean onKeyDown(int keyCode, KeyEvent event) {
591 | if (keyCode == KeyEvent.KEYCODE_BACK) {
592 | if (x5WebView != null && x5WebView.canGoBack()){
593 | x5WebView.goBack();// 返回前一个页面
594 | return true;
595 | }else if (mSystemWebView != null && mSystemWebView.canGoBack()){
596 | mSystemWebView.goBack();// 返回前一个页面
597 | return true;
598 | }
599 |
600 | setIdelView();
601 | }
602 | return super.onKeyDown(keyCode, event);
603 | }
604 |
605 | private void setIdelView() {
606 | if (idel_layout != null){
607 | mParentView.removeAllViews();
608 | mParentView.addView(idel_layout);
609 | }
610 | }
611 |
612 | @Override
613 | public void onBackPressed() {
614 | AlertDialog.Builder builder;
615 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
616 | builder = new AlertDialog.Builder(MainActivity.this, android.R.style.Theme_Material_Light_Dialog_Alert);
617 | } else {
618 | builder = new AlertDialog.Builder(MainActivity.this);
619 | }
620 | builder.setIcon(R.mipmap.ic_launcher).setTitle("提示").setMessage("是否退出应用?").setNegativeButton("否", new DialogInterface.OnClickListener() {
621 | @Override
622 | public void onClick(DialogInterface dialogInterface, int i) {
623 | dialogInterface.dismiss();
624 | }
625 | }).setPositiveButton("是", new DialogInterface.OnClickListener() {
626 | @Override
627 | public void onClick(DialogInterface dialogInterface, int i) {
628 | finish();
629 | }
630 | }).create().show();
631 | }
632 | }
633 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/NativeToJsActivity.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.os.Message;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.os.Bundle;
8 | import android.util.Log;
9 | import android.view.View;
10 | import android.webkit.JavascriptInterface;
11 | import android.widget.EditText;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.sunteng.x5webenginedemo.Tool.WebViewJavaScriptFunction;
16 | import com.sunteng.x5webenginedemo.Tool.X5WebView;
17 |
18 | public class NativeToJsActivity extends AppCompatActivity implements View.OnClickListener {
19 |
20 | private EditText nativeToJsEdit;
21 | private TextView nativeToJsNumTextView;
22 |
23 |
24 | private Handler handler;
25 |
26 | private static final int MSG=0;
27 | private static final int NUM=1;
28 | private static final int MSG_SUBMIT=2;
29 | private static final int CLOSE_SUBMIT=3;
30 |
31 | private int num=0;
32 | private String msg="X5 WebView";
33 |
34 | private X5WebView mWebView;
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.native_js_activity);
40 |
41 | this.handler=new Handler(Looper.myLooper()){
42 |
43 | @Override
44 | public void handleMessage(Message msg) {
45 | // TODO Auto-generated method stub
46 | switch(msg.what){
47 | case NUM:
48 | NativeToJsActivity.this.nativeToJsNumTextView.setText(String.valueOf(num));
49 | break;
50 | case MSG:
51 | NativeToJsActivity.this.nativeToJsEdit.setText(NativeToJsActivity.this.msg);
52 | break;
53 | case MSG_SUBMIT:
54 | NativeToJsActivity.this.msg = NativeToJsActivity.this.nativeToJsEdit.getEditableText().toString();
55 | break;
56 | case CLOSE_SUBMIT:
57 | Toast.makeText(NativeToJsActivity.this.getApplicationContext() , "Js 异步触发 Android 窗口关闭事件", Toast.LENGTH_SHORT).show();
58 | break;
59 | }
60 | super.handleMessage(msg);
61 |
62 | }
63 |
64 | };
65 | mWebView = (X5WebView) findViewById(R.id.x5web_native2js);
66 | mWebView.loadUrl("file:///android_asset/webpage/jsToJava.html");
67 |
68 | mWebView.addJavascriptInterface(new WebViewJavaScriptFunction() {
69 |
70 | @Override
71 | public void onJsFunctionCalled(String tag) {
72 | // TODO Auto-generated method stub
73 | Log.i("jsToAndroid","onJsFunctionCalled tag : " + tag);
74 | }
75 | ///////////////////////////////////////////////
76 | //javascript to java methods
77 | @JavascriptInterface
78 | public void onSubmit(String s){
79 | Log.i("jsToAndroid","onSubmit happend! " + s);
80 | NativeToJsActivity.this.msg = s;
81 | Message.obtain(handler, MSG).sendToTarget();
82 | }
83 |
84 | @JavascriptInterface
85 | public void onSubmitNum(String s){
86 | Log.i("jsToAndroid","onSubmitNum happend! " + s);
87 | NativeToJsActivity.this.num = Integer.parseInt(s);
88 | Message.obtain(handler, NUM).sendToTarget();
89 | }
90 |
91 |
92 | /**
93 | * java 调用 js方法 并且 传值
94 | * 步骤:1、调用 js函数 2、js回调一个android方法得到参数 3、js处理函数
95 | * @return
96 | */
97 | @JavascriptInterface
98 | public String getAndroidMsg(){
99 | Log.i("jsToAndroid","onSubmitNum happend!");
100 | return NativeToJsActivity.this.msg;
101 | }
102 |
103 | @JavascriptInterface
104 | public String getAndroidNum(){
105 | Log.i("jsToAndroid","onSubmitNum happend!");
106 | return String.valueOf(NativeToJsActivity.this.num);
107 | }
108 |
109 |
110 |
111 | /**
112 | * 各种类型的传递
113 | */
114 | @JavascriptInterface
115 | public void getManyValue(String key,String value){
116 |
117 | Log.i("jsToAndroid", "get key is:"+key+" value is:"+value);
118 | }
119 |
120 | /**
121 | * 关闭当前的窗口
122 | */
123 | @JavascriptInterface
124 | public void closeCurrentWindow(){
125 | Message.obtain(handler, CLOSE_SUBMIT).sendToTarget();
126 | NativeToJsActivity.this.finish();
127 | }
128 | }, "Android");
129 |
130 | initView();
131 | }
132 |
133 | private void initView() {
134 |
135 | nativeToJsEdit = (EditText)findViewById(R.id.edit_native_js_edit);
136 | this.nativeToJsEdit.setHint("输入与js交互的内容");
137 |
138 | nativeToJsNumTextView = (TextView)findViewById(R.id.text_native_js_num);
139 | this.nativeToJsNumTextView.setText("" + this.num);
140 |
141 | findViewById(R.id.bt_native_js_edit).setOnClickListener(this);
142 | findViewById(R.id.bt_native_js_num_add).setOnClickListener(this);
143 | findViewById(R.id.bt_native_js_num_minuse).setOnClickListener(this);
144 | findViewById(R.id.web_native_js_close_btn).setOnClickListener(this);
145 | }
146 |
147 | @Override
148 | public void onClick(View v) {
149 |
150 | int num = Integer.parseInt(NativeToJsActivity.this.nativeToJsNumTextView.getText().toString());
151 |
152 | switch (v.getId()){
153 | case R.id.bt_native_js_edit:
154 | Message.obtain(handler, MSG_SUBMIT).sendToTarget();
155 | NativeToJsActivity.this.mWebView.loadUrl("javascript:returnMsg()");
156 | break;
157 | case R.id.web_native_js_close_btn:
158 | NativeToJsActivity.this.mWebView.loadUrl("javascript:closeWnd()");
159 | break;
160 | case R.id.bt_native_js_num_add:
161 | NativeToJsActivity.this.num++;
162 | NativeToJsActivity.this.num=(++num);
163 | Message.obtain(handler, NUM).sendToTarget();
164 | NativeToJsActivity.this.mWebView.loadUrl("javascript:returnNum()");
165 | break;
166 | case R.id.bt_native_js_num_minuse:
167 | NativeToJsActivity.this.num=(--num);
168 | NativeToJsActivity.this.mWebView.loadUrl("javascript:returnNum()");
169 | break;
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/RefreshActivity.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 |
4 | import android.app.Activity;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.Button;
8 | import android.widget.TextView;
9 |
10 | import com.sunteng.x5webenginedemo.Tool.X5WebView;
11 |
12 | public class RefreshActivity extends Activity{
13 | X5WebView webView;
14 | TextView title;
15 |
16 | /**
17 | * 此类实现了下拉刷新,
18 | * 使用extension interface将会准确回去overScroll的时机
19 | *
20 | */
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.refresh_layout);
26 | webView=(X5WebView)findViewById(R.id.web_filechooser);
27 | title = (TextView) findViewById(R.id.refreshText);
28 | webView.setTitle(title);
29 | webView.loadUrl("http://app.html5.qq.com/navi/index");
30 | this.initBtn();
31 | }
32 |
33 | private void initBtn(){
34 | Button btnFlush=(Button) findViewById(R.id.bt_filechooser_flush);
35 | btnFlush.setOnClickListener(new View.OnClickListener() {
36 | @Override
37 | public void onClick(View v) {
38 | webView.reload();
39 | //webView.setDayOrNight(false);
40 | }
41 | });
42 |
43 | Button btnBackForward=(Button) findViewById(R.id.bt_filechooser_back);
44 | btnBackForward.setOnClickListener(new View.OnClickListener() {
45 |
46 | @Override
47 | public void onClick(View v) {
48 | webView.goBack();
49 | }
50 | });
51 |
52 | Button btnHome=(Button) findViewById(R.id.bt_filechooser_home);
53 | btnHome.setOnClickListener(new View.OnClickListener() {
54 |
55 | @Override
56 | public void onClick(View v) {
57 | webView.loadUrl("http://app.html5.qq.com/navi/index");
58 | }
59 | });
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/Tool/SecurityJsBridgeBundle.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo.Tool;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.Map;
6 |
7 | public abstract class SecurityJsBridgeBundle {
8 |
9 |
10 | ///////////////////////////////////////////////////////////////////////////////
11 | //add js
12 | private final static String DEFAULT_JS_BRIDGE ="JsBridge";
13 | public static final String METHOD = "method";
14 | public static final String BLOCK = "block";
15 | public static final String CALLBACK = "callback";
16 |
17 | public static final String PROMPT_START_OFFSET = "local_js_bridge::";
18 |
19 | private Context mContext;
20 | private String mJsBlockName ;
21 | private String mMethodName;
22 |
23 |
24 | public abstract void onCallMethod();
25 |
26 | public SecurityJsBridgeBundle(String JsBlockName, String methodName) throws Exception{
27 | if(methodName == null){
28 | throw new Exception("methodName can not be null!");
29 | }
30 |
31 | if(JsBlockName!=null){
32 | this.mJsBlockName=JsBlockName;
33 | }else{
34 | this.mJsBlockName = DEFAULT_JS_BRIDGE;
35 | }
36 |
37 |
38 | }
39 |
40 |
41 | public String getMethodName(){
42 | return this.mMethodName;
43 | }
44 |
45 | public String getJsBlockName(){
46 | return this.mJsBlockName;
47 | }
48 |
49 |
50 | private void injectJsMsgPipecode(Map data){
51 | if(data==null){
52 | return ;
53 | }
54 | String injectCode = "javascript:(function JsAddJavascriptInterface_(){ "+
55 | "if (typeof(window.jsInterface)!='undefined') {"+
56 | "console.log('window.jsInterface_js_interface_name is exist!!');} "+
57 | "else {"+
58 | data.get(BLOCK)+data.get(METHOD)+
59 | "window.jsBridge = {"+
60 | "onButtonClick:function(arg0) {"+
61 | "return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]}));"+
62 | "},"+
63 |
64 | "onImageClick:function(arg0,arg1,arg2) {"+
65 | "prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]}));"+
66 | "},"+
67 | "};"+
68 | "}"+
69 | "}"+
70 | ")()";
71 | }
72 |
73 |
74 | private static String getStandardMethodSignature(){
75 | return null;
76 | }
77 |
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/Tool/WebViewJavaScriptFunction.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo.Tool;
2 |
3 | public interface WebViewJavaScriptFunction {
4 |
5 | void onJsFunctionCalled(String tag);
6 | }
7 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/Tool/X5WebView.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo.Tool;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Paint;
10 | import android.net.Uri;
11 | import android.os.Build;
12 | import android.os.Message;
13 | import android.util.AttributeSet;
14 | import android.util.Log;
15 | import android.view.Gravity;
16 | import android.view.MotionEvent;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 | import android.widget.FrameLayout;
20 | import android.widget.RelativeLayout;
21 | import android.widget.TextView;
22 |
23 | import com.sunteng.x5webenginedemo.R;
24 | import com.sunteng.x5webenginedemo.RefreshActivity;
25 | import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
26 | import com.tencent.smtt.export.external.interfaces.JsPromptResult;
27 | import com.tencent.smtt.export.external.interfaces.JsResult;
28 | import com.tencent.smtt.sdk.QbSdk;
29 | import com.tencent.smtt.sdk.ValueCallback;
30 | import com.tencent.smtt.sdk.WebChromeClient;
31 | import com.tencent.smtt.sdk.WebSettings;
32 | import com.tencent.smtt.sdk.WebView;
33 | import com.tencent.smtt.sdk.WebViewClient;
34 |
35 | import java.util.HashMap;
36 | import java.util.Map;
37 |
38 | public class X5WebView extends WebView {
39 |
40 | public static final int FILE_CHOOSER = 0;
41 | private String resourceUrl = "";
42 | private WebView smallWebView;
43 | private static boolean isSmallWebViewDisplayed = false;
44 | private boolean isClampedY = false;
45 | private Map mJsBridges;
46 | private TextView tog;
47 | RelativeLayout.LayoutParams layoutParams;
48 | private RelativeLayout refreshRela;
49 | TextView title;
50 |
51 | public X5WebView(Context context) {
52 | super(context);
53 | setBackgroundColor(85621);
54 | }
55 |
56 | @SuppressLint("SetJavaScriptEnabled")
57 | public X5WebView(Context context, AttributeSet attributeSet) {
58 | super(context, attributeSet);
59 | this.setWebViewClientExtension(new X5WebViewEventHandler(this));// 配置X5webview的事件处理
60 | this.setWebViewClient(client);
61 | this.setWebChromeClient(chromeClient);
62 | //WebStorage webStorage = WebStorage.getInstance();
63 | initWebViewSettings();
64 | this.getView().setClickable(true);
65 | this.getView().setOnTouchListener(new OnTouchListener() {
66 | @Override
67 | public boolean onTouch(View v, MotionEvent event) {
68 | return false;
69 | }
70 | });
71 | }
72 |
73 | private void initWebViewSettings() {
74 | WebSettings webSetting = this.getSettings();
75 | webSetting.setJavaScriptEnabled(true);
76 | webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
77 | webSetting.setAllowFileAccess(true);
78 | webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
79 | webSetting.setSupportZoom(true);
80 | webSetting.setBuiltInZoomControls(true);
81 | webSetting.setUseWideViewPort(true);
82 | webSetting.setSupportMultipleWindows(true);
83 | //webSetting.setLoadWithOverviewMode(true);
84 | webSetting.setAppCacheEnabled(true);
85 | //webSetting.setDatabaseEnabled(true);
86 | webSetting.setDomStorageEnabled(true);
87 | webSetting.setGeolocationEnabled(true);
88 | webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
89 | // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
90 | webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
91 | //webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
92 | webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);
93 |
94 | // this.getSettingsExtension().setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);//extension settings 的设计
95 | }
96 |
97 | @Override
98 | protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
99 | boolean ret = super.drawChild(canvas, child, drawingTime);
100 | canvas.save();
101 | Paint paint = new Paint();
102 | paint.setColor(0x7fff0000);
103 | paint.setTextSize(24.f);
104 | paint.setAntiAlias(true);
105 | if (getX5WebViewExtension() != null) {
106 | canvas.drawText(this.getContext().getPackageName() + "-pid:" + android.os.Process.myPid(), 10, 50, paint);
107 | canvas.drawText("X5 Core:" + QbSdk.getTbsVersion(this.getContext()), 10, 100, paint);
108 | } else {
109 | canvas.drawText(this.getContext().getPackageName() + "-pid:" + android.os.Process.myPid(), 10, 50, paint);
110 | canvas.drawText("Sys Core", 10, 100, paint);
111 | }
112 | canvas.drawText(Build.MANUFACTURER, 10, 150, paint);
113 | canvas.drawText(Build.MODEL, 10, 200, paint);
114 | canvas.restore();
115 | return ret;
116 | }
117 |
118 | private WebViewClient client = new WebViewClient() {
119 | /**
120 | * 防止加载网页时调起系统浏览器
121 | */
122 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
123 | view.loadUrl(url);
124 | return true;
125 | }
126 |
127 | public void onReceivedHttpAuthRequest(WebView webview,
128 | com.tencent.smtt.export.external.interfaces.HttpAuthHandler httpAuthHandlerhost, String host,
129 | String realm) {
130 | boolean flag = httpAuthHandlerhost.useHttpAuthUsernamePassword();
131 | }
132 | };
133 |
134 | private WebChromeClient chromeClient = new WebChromeClient() {
135 |
136 | @Override
137 | public boolean onJsConfirm(WebView arg0, String arg1, String arg2, JsResult arg3) {
138 | return super.onJsConfirm(arg0, arg1, arg2, arg3);
139 | }
140 |
141 | View myVideoView;
142 | View myNormalView;
143 | IX5WebChromeClient.CustomViewCallback callback;
144 |
145 | ///////////////////////////////////////////////////////////
146 | //
147 | /**
148 | * 全屏播放配置
149 | */
150 | @Override
151 | public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback customViewCallback) {
152 | FrameLayout normalView = (FrameLayout) ((Activity) getContext()).findViewById(R.id.web_filechooser);
153 | ViewGroup viewGroup = (ViewGroup) normalView.getParent();
154 | viewGroup.removeView(normalView);
155 | viewGroup.addView(view);
156 | myVideoView = view;
157 | myNormalView = normalView;
158 | callback = customViewCallback;
159 | }
160 |
161 | @Override
162 | public void onHideCustomView() {
163 | if (callback != null) {
164 | callback.onCustomViewHidden();
165 | callback = null;
166 | }
167 | if (myVideoView != null) {
168 | ViewGroup viewGroup = (ViewGroup) myVideoView.getParent();
169 | viewGroup.removeView(myVideoView);
170 | viewGroup.addView(myNormalView);
171 | }
172 | }
173 |
174 | @Override
175 | public boolean onShowFileChooser(WebView arg0,
176 | ValueCallback arg1, FileChooserParams arg2) {
177 | // TODO Auto-generated method stub
178 | Log.e("app", "onShowFileChooser");
179 | return super.onShowFileChooser(arg0, arg1, arg2);
180 | }
181 |
182 | @Override
183 | public void openFileChooser(ValueCallback uploadFile, String acceptType, String captureType) {
184 | Log.e("app", "openFileChooser");
185 | Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
186 | intent.setType("*/*");
187 | intent.addCategory(Intent.CATEGORY_OPENABLE);
188 | try
189 | {
190 | ((Activity) (X5WebView.this.getContext())).startActivityForResult(Intent.createChooser(intent, "choose files"),
191 | 1);
192 | }
193 | catch (android.content.ActivityNotFoundException ex)
194 | {
195 |
196 | }
197 |
198 | super.openFileChooser(uploadFile, acceptType, captureType);
199 | }
200 | /**
201 | * webview 的窗口转移
202 | */
203 | @Override
204 | public boolean onCreateWindow(WebView arg0, boolean arg1, boolean arg2, Message msg) {
205 | // TODO Auto-generated method stub
206 | if (X5WebView.isSmallWebViewDisplayed == true) {
207 |
208 | WebView.WebViewTransport webViewTransport = (WebView.WebViewTransport) msg.obj;
209 | WebView webView = new WebView(X5WebView.this.getContext()) {
210 |
211 | protected void onDraw(Canvas canvas) {
212 | super.onDraw(canvas);
213 | Paint paint = new Paint();
214 | paint.setColor(Color.GREEN);
215 | paint.setTextSize(15);
216 | canvas.drawText("新建窗口", 10, 10, paint);
217 | };
218 | };
219 | webView.setWebViewClient(new WebViewClient() {
220 | public boolean shouldOverrideUrlLoading(WebView arg0, String arg1) {
221 | arg0.loadUrl(arg1);
222 | return true;
223 | };
224 | });
225 | FrameLayout.LayoutParams lp = new LayoutParams(400, 600);
226 | lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
227 | X5WebView.this.addView(webView, lp);
228 | webViewTransport.setWebView(webView);
229 | msg.sendToTarget();
230 | }
231 | return true;
232 | }
233 |
234 | @Override
235 | public boolean onJsAlert(WebView arg0, String arg1, String arg2, JsResult arg3) {
236 | /**
237 | * 这里写入你自定义的window alert
238 | */
239 | // AlertDialog.Builder builder = new Builder(getContext());
240 | // builder.setTitle("X5内核");
241 | // builder.setPositiveButton("确定", new
242 | // DialogInterface.OnClickListener() {
243 | //
244 | // @Override
245 | // public void onClick(DialogInterface dialog, int which) {
246 | // // TODO Auto-generated method stub
247 | // dialog.dismiss();
248 | // }
249 | // });
250 | // builder.show();
251 | // arg3.confirm();
252 | // return true;
253 | Log.i("yuanhaizhou", "setX5webview = null");
254 | return super.onJsAlert(null, "www.baidu.com", "aa", arg3);
255 | }
256 |
257 | /**
258 | * 对应js 的通知弹框 ,可以用来实现js 和 android之间的通信
259 | */
260 | @Override
261 | public boolean onJsPrompt(WebView arg0, String arg1, String arg2, String arg3, JsPromptResult arg4) {
262 | // 在这里可以判定js传过来的数据,用于调起android native 方法
263 | if (X5WebView.this.isMsgPrompt(arg1)) {
264 | if (X5WebView.this.onJsPrompt(arg2, arg3)) {
265 | return true;
266 | } else {
267 | return false;
268 | }
269 | }
270 | return super.onJsPrompt(arg0, arg1, arg2, arg3, arg4);
271 | }
272 |
273 | @Override
274 | public void onReceivedTitle(WebView arg0, final String arg1) {
275 | super.onReceivedTitle(arg0, arg1);
276 | Log.i("yuanhaizhou", "webpage title is " + arg1);
277 |
278 | }
279 | };
280 |
281 | public static void setSmallWebViewEnabled(boolean enabled) {
282 | isSmallWebViewDisplayed = enabled;
283 | }
284 |
285 | public void addJavascriptBridge(SecurityJsBridgeBundle jsBridgeBundle) {
286 | if (this.mJsBridges == null) {
287 | this.mJsBridges = new HashMap(5);
288 | }
289 |
290 | if (jsBridgeBundle != null) {
291 | String tag = SecurityJsBridgeBundle.BLOCK + jsBridgeBundle.getJsBlockName() + "-"
292 | + SecurityJsBridgeBundle.METHOD + jsBridgeBundle.getMethodName();
293 | this.mJsBridges.put(tag, jsBridgeBundle);
294 | }
295 | }
296 |
297 | /**
298 | * 当webchromeClient收到 web的prompt请求后进行拦截判断,用于调起本地android方法
299 | *
300 | * @param methodName
301 | * 方法名称
302 | * @param blockName
303 | * 区块名称
304 | * @return true :调用成功 ; false :调用失败
305 | */
306 | private boolean onJsPrompt(String methodName, String blockName) {
307 | String tag = SecurityJsBridgeBundle.BLOCK + blockName + "-" + SecurityJsBridgeBundle.METHOD + methodName;
308 |
309 | if (this.mJsBridges != null && this.mJsBridges.containsKey(tag)) {
310 | ((SecurityJsBridgeBundle) this.mJsBridges.get(tag)).onCallMethod();
311 | return true;
312 | } else {
313 | return false;
314 | }
315 | }
316 |
317 | /**
318 | * 判定当前的prompt消息是否为用于调用native方法的消息
319 | *
320 | * @param msg
321 | * 消息名称
322 | * @return true 属于prompt消息方法的调用
323 | */
324 | private boolean isMsgPrompt(String msg) {
325 | if (msg != null && msg.startsWith(SecurityJsBridgeBundle.PROMPT_START_OFFSET)) {
326 | return true;
327 | } else {
328 | return false;
329 | }
330 | }
331 |
332 | // TBS: Do not use @Override to avoid false calls
333 | public boolean tbs_dispatchTouchEvent(MotionEvent ev, View view) {
334 | boolean r = super.super_dispatchTouchEvent(ev);
335 | Log.d("Bran", "dispatchTouchEvent " + ev.getAction() + " " + r);
336 | return r;
337 | }
338 |
339 | // TBS: Do not use @Override to avoid false calls
340 | public boolean tbs_onInterceptTouchEvent(MotionEvent ev, View view) {
341 | boolean r = super.super_onInterceptTouchEvent(ev);
342 | return r;
343 | }
344 |
345 | protected void tbs_onScrollChanged(int l, int t, int oldl, int oldt, View view) {
346 | super_onScrollChanged(l, t, oldl, oldt);
347 | }
348 |
349 | protected void tbs_onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY, View view) {
350 | if (getContext() instanceof RefreshActivity) {
351 | if (this.tog == null) {
352 | this.tog = (TextView) ((Activity) getContext()).findViewById(R.id.refreshText);
353 | layoutParams = (RelativeLayout.LayoutParams) (this.tog.getLayoutParams());
354 | this.refreshRela = (RelativeLayout) ((Activity) getContext()).findViewById(R.id.refreshPool);
355 | }
356 | if (isClampedY && !clampedY) {
357 | this.reload();
358 | }
359 | if (clampedY) {
360 | this.isClampedY = true;
361 |
362 | } else {
363 | this.isClampedY = false;
364 | }
365 | }
366 | super_onOverScrolled(scrollX, scrollY, clampedX, clampedY);
367 | }
368 |
369 | protected void tbs_computeScroll(View view) {
370 | super_computeScroll();
371 | }
372 |
373 | protected boolean tbs_overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
374 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent, View view) {
375 | if (getContext() instanceof RefreshActivity) {
376 | if (this.isClampedY) {
377 | if ((refreshRela.getTop() + (-deltaY)) / 2 < 255) {
378 | this.tog.setAlpha((refreshRela.getTop() + (-deltaY)) / 2);
379 | } else
380 | this.tog.setAlpha(255);
381 | this.refreshRela.layout(refreshRela.getLeft(), refreshRela.getTop() + (-deltaY), refreshRela.getRight(),
382 | refreshRela.getBottom() + (-deltaY));
383 | this.layout(this.getLeft(), this.getTop() + (-deltaY) / 2, this.getRight(),
384 | this.getBottom() + (-deltaY) / 2);
385 | }
386 | }
387 | return super_overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX,
388 | maxOverScrollY, isTouchEvent);
389 | }
390 |
391 | public void setTitle(TextView title) {
392 | this.title = title;
393 | }
394 |
395 | protected boolean tbs_onTouchEvent(MotionEvent event, View view) {
396 | if (getContext() instanceof RefreshActivity) {
397 | if (event.getAction() == MotionEvent.ACTION_UP && this.tog != null) {
398 | this.isClampedY = false;
399 | this.tog.setAlpha(0);
400 | this.refreshRela.layout(refreshRela.getLeft(), 0, refreshRela.getRight(), refreshRela.getBottom());
401 | this.layout(this.getLeft(), 0, this.getRight(), this.getBottom());
402 | }
403 |
404 | }
405 | return super_onTouchEvent(event);
406 | }
407 |
408 | }
409 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/Tool/X5WebViewEventHandler.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo.Tool;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.os.Message;
7 | import android.util.Log;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.view.ViewGroup.LayoutParams;
11 | import android.webkit.ValueCallback;
12 |
13 | import com.tencent.smtt.export.external.extension.interfaces.IX5WebChromeClientExtension;
14 | import com.tencent.smtt.export.external.extension.interfaces.IX5WebViewExtension;
15 | import com.tencent.smtt.export.external.extension.proxy.ProxyWebViewClientExtension;
16 | import com.tencent.smtt.export.external.interfaces.IX5WebViewBase.HitTestResult;
17 | import com.tencent.smtt.export.external.interfaces.JsResult;
18 | import com.tencent.smtt.export.external.interfaces.MediaAccessPermissionsCallback;
19 | import com.tencent.smtt.sdk.WebViewCallbackClient;
20 |
21 | import java.util.HashMap;
22 |
23 | public class X5WebViewEventHandler extends ProxyWebViewClientExtension implements IX5WebChromeClientExtension {
24 |
25 | /**
26 | * 这个类用于实现由于X5webview适配架构导致的部分client回调不会发生,或者回调中传入的值不正确
27 | * 这个方法中所有的interface均是直接从内核中获取值并传入内核,请谨慎修改
28 | * 使用时只需要在对应的方法中加入你自己的逻辑就可以
29 | * 同时注意:具有返回值的方法在正常情况下保持其返回效果
30 | * 一般而言:返回true表示消费事件,由用户端直接处理事件
31 | * 返回false表示需要内核使用默认机制处理事件
32 | */
33 | private X5WebView webView; //the vote of x5webview
34 |
35 | public X5WebViewEventHandler(X5WebView webView){
36 | this.webView = webView;
37 | this.webView.setWebViewCallbackClient(callbackClient);
38 |
39 | }
40 |
41 | @Override
42 | public void acquireWakeLock() {
43 | // TODO Auto-generated method stub
44 |
45 | }
46 |
47 | @Override
48 | public void addFlashView(View arg0, LayoutParams arg1) {
49 | // TODO Auto-generated method stub
50 |
51 | }
52 |
53 | @Override
54 | public void exitFullScreenFlash() {
55 | // TODO Auto-generated method stub
56 |
57 | }
58 |
59 | @Override
60 | public Context getApplicationContex() {
61 | // TODO Auto-generated method stub
62 | return null;
63 | }
64 |
65 | @Override
66 | public View getVideoLoadingProgressView() {
67 | // TODO Auto-generated method stub
68 | return null;
69 | }
70 |
71 | @Override
72 | public Object getX5WebChromeClientInstance() {
73 | // TODO Auto-generated method stub
74 | return null;
75 | }
76 |
77 | @Override
78 | public void h5videoExitFullScreen(String arg0) {
79 | // TODO Auto-generated method stub
80 |
81 | }
82 |
83 | @Override
84 | public void h5videoRequestFullScreen(String arg0) {
85 | // TODO Auto-generated method stub
86 |
87 | }
88 |
89 | @Override
90 | public boolean onAddFavorite(IX5WebViewExtension arg0, String arg1,
91 | String arg2, JsResult arg3) {
92 | // TODO Auto-generated method stub
93 | return false;
94 | }
95 |
96 | @Override
97 | public void onAllMetaDataFinished(IX5WebViewExtension arg0,
98 | HashMap arg1) {
99 | // TODO Auto-generated method stub
100 |
101 | }
102 |
103 | @Override
104 | public void onBackforwardFinished(int arg0) {
105 | // TODO Auto-generated method stub
106 |
107 | }
108 |
109 | @Override
110 | public void onHitTestResultFinished(IX5WebViewExtension arg0,
111 | HitTestResult arg1) {
112 | // TODO Auto-generated method stub
113 | Log.i("yuanhaizhou", "onHitTestResultFinished");
114 | }
115 |
116 | @Override
117 | public void onHitTestResultForPluginFinished(IX5WebViewExtension arg0,
118 | HitTestResult arg1, Bundle arg2) {
119 | // TODO Auto-generated method stub
120 | arg1.getData();
121 | Log.i("yuanhaizhou", "onHitTestResultForPluginFinished");
122 | }
123 |
124 | @Override
125 | public boolean onPageNotResponding(Runnable arg0) {
126 | // TODO Auto-generated method stub
127 | return false;
128 | }
129 |
130 | @Override
131 | public void onPrepareX5ReadPageDataFinished(IX5WebViewExtension arg0,
132 | HashMap arg1) {
133 | // TODO Auto-generated method stub
134 |
135 | }
136 |
137 | @Override
138 | public void onPromptNotScalable(IX5WebViewExtension arg0) {
139 | // TODO Auto-generated method stub
140 |
141 | }
142 |
143 | @Override
144 | public void onPromptScaleSaved(IX5WebViewExtension arg0) {
145 | // TODO Auto-generated method stub
146 |
147 | }
148 |
149 | @Override
150 | public boolean onSavePassword(String arg0, String arg1, String arg2,
151 | boolean arg3, Message arg4) {
152 | // TODO Auto-generated method stub
153 | return false;
154 | }
155 |
156 | @Override
157 | public void onX5ReadModeAvailableChecked(HashMap arg0) {
158 | // TODO Auto-generated method stub
159 |
160 | }
161 |
162 | @Override
163 | public void releaseWakeLock() {
164 | // TODO Auto-generated method stub
165 |
166 | }
167 |
168 | @Override
169 | public void requestFullScreenFlash() {
170 | // TODO Auto-generated method stub
171 |
172 | }
173 |
174 |
175 | /////////////////////////////////////////////////////
176 |
177 | /**
178 | * 这里使用内核的事件回调链接到对应webview的事件回调
179 | */
180 | private WebViewCallbackClient callbackClient = new WebViewCallbackClient() {
181 |
182 | @Override
183 | public boolean onTouchEvent(MotionEvent event, View view) {
184 | Log.i("yuanhaizhou", "tbs_onTouchEvent view is " + view.getClass().toString());
185 | return webView.tbs_onTouchEvent(event, view);
186 | }
187 |
188 |
189 | @Override
190 | public boolean overScrollBy(int deltaX, int deltaY, int scrollX,
191 | int scrollY, int scrollRangeX, int scrollRangeY,
192 | int maxOverScrollX, int maxOverScrollY,
193 | boolean isTouchEvent, View view) {
194 | return webView.tbs_overScrollBy(deltaX, deltaY, scrollX, scrollY,
195 | scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY,
196 | isTouchEvent, view);
197 | }
198 |
199 | @Override
200 | public void computeScroll(View view) {
201 | webView.tbs_computeScroll(view);
202 | }
203 |
204 |
205 | @Override
206 | public void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
207 | boolean clampedY, View view) {
208 | webView.tbs_onOverScrolled(scrollX, scrollY, clampedX, clampedY, view);
209 | }
210 |
211 | @Override
212 | public void onScrollChanged(int l, int t, int oldl, int oldt, View view) {
213 | webView.tbs_onScrollChanged(l, t, oldl, oldt, view);
214 | }
215 |
216 | @Override
217 | public boolean dispatchTouchEvent(MotionEvent ev, View view) {
218 | return webView.tbs_dispatchTouchEvent(ev, view);
219 | }
220 |
221 | @Override
222 | public boolean onInterceptTouchEvent(MotionEvent ev, View view) {
223 | return webView.tbs_onInterceptTouchEvent(ev, view);
224 | }
225 | };
226 |
227 |
228 | //////////////////////////////////////////////////////////////////////
229 | /**
230 | * 这里是内核代理的事件处理方法
231 | */
232 |
233 | @Override
234 | public Object onMiscCallBack(String method,
235 | Bundle bundle) {
236 |
237 | return null;
238 | }
239 |
240 | @Override
241 | public boolean onTouchEvent(MotionEvent event, View view) {
242 | return callbackClient.onTouchEvent(event, view);
243 | }
244 |
245 | // 1
246 | public boolean onInterceptTouchEvent(MotionEvent ev, View view) {
247 | return callbackClient.onInterceptTouchEvent(ev, view);
248 | }
249 |
250 | // 3
251 | public boolean dispatchTouchEvent(MotionEvent ev, View view) {
252 | return callbackClient.dispatchTouchEvent(ev, view);
253 | }
254 | // 4
255 | public boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
256 | int scrollRangeX, int scrollRangeY,
257 | int maxOverScrollX, int maxOverScrollY,
258 | boolean isTouchEvent, View view) {
259 | return callbackClient.overScrollBy(deltaX, deltaY, scrollX, scrollY,
260 | scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent, view);
261 | }
262 | // 5
263 | public void onScrollChanged(int l, int t, int oldl, int oldt, View view) {
264 | callbackClient.onScrollChanged(l, t, oldl, oldt, view);
265 | }
266 | // 6
267 | public void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
268 | boolean clampedY, View view) {
269 | callbackClient.onOverScrolled(scrollX, scrollY, clampedX, clampedY, view);
270 | }
271 | // 7
272 | public void computeScroll(View view) {
273 | callbackClient.computeScroll(view);
274 | }
275 |
276 | @Override
277 | public void onPrintPage() {
278 | // TODO Auto-generated method stub
279 |
280 | }
281 |
282 | @Override
283 | public boolean onSavePassword(ValueCallback arg0, String arg1,
284 | String arg2, String arg3, String arg4, String arg5, boolean arg6) {
285 | // TODO Auto-generated method stub
286 | return false;
287 | }
288 |
289 | @Override
290 | public void openFileChooser(ValueCallback arg0, String arg1,
291 | String arg2) {
292 | // TODO Auto-generated method stub
293 |
294 | }
295 |
296 |
297 |
298 | @Override
299 | public void onColorModeChanged(long arg0) {
300 | // TODO Auto-generated method stub
301 |
302 | }
303 |
304 | @Override
305 | public void jsExitFullScreen() {
306 | // TODO Auto-generated method stub
307 |
308 | }
309 |
310 | @Override
311 | public void jsRequestFullScreen() {
312 | // TODO Auto-generated method stub
313 |
314 | }
315 |
316 | @Override
317 | public boolean onPermissionRequest(String arg0, long arg1,
318 | MediaAccessPermissionsCallback arg2) {
319 | // TODO Auto-generated method stub
320 | return false;
321 | }
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 | }
333 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/java/com/sunteng/x5webenginedemo/X5Application.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
2 |
3 | import android.app.Application;
4 | import android.content.Intent;
5 |
6 | /**
7 | * X5WebEngineDemo Created by baishixian on 2017/1/19.
8 | */
9 |
10 | public class X5Application extends Application {
11 |
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | initX5();
16 | }
17 |
18 | private void initX5() {
19 | Intent intent = new Intent(this, AdvanceLoadX5Service.class);
20 | startService(intent);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/jniLibs/armeabi/liblbs.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/jniLibs/armeabi/liblbs.so
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
39 |
40 |
46 |
47 |
53 |
54 |
60 |
61 |
66 |
67 |
68 |
69 |
70 |
71 |
78 |
84 |
97 |
109 |
120 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/layout/activity_native_to_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/layout/game_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/layout/native_js_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
25 |
26 |
32 |
33 |
34 |
42 |
43 |
44 |
45 |
46 |
52 |
53 |
58 |
59 |
64 |
74 |
80 |
81 |
82 |
87 |
92 |
97 |
102 |
103 |
104 |
111 |
112 |
113 |
114 |
115 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/layout/refresh_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
12 |
18 |
19 |
23 |
24 |
30 |
31 |
32 |
36 |
37 |
43 |
44 |
45 |
49 |
50 |
56 |
57 |
58 |
59 |
63 |
64 |
71 |
72 |
76 |
77 |
78 |
86 |
87 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/mipmap-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/res/mipmap-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | X5WebEngineDemo
3 |
4 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/app/src/test/java/com/sunteng/x5webenginedemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.sunteng.x5webenginedemo;
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 | }
--------------------------------------------------------------------------------
/X5WebEngineDemo/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/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 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5WebEngineDemo/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/X5WebEngineDemo/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/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 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/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 |
--------------------------------------------------------------------------------
/X5WebEngineDemo/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/X5浏览器内核调研报告.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baishixian/X5WebEngineDemo/ac83a456942575c1385ee744d1651f309eb06cdb/X5浏览器内核调研报告.pdf
--------------------------------------------------------------------------------