├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml ├── sonarlint │ └── issuestore │ │ ├── 2 │ │ └── e │ │ │ └── 2e2a2e3942428376ce753cdebd1f1e8adac20864 │ │ ├── 3 │ │ └── 9 │ │ │ └── 39420a7303320a28a2f4d7fde496348ac4153e0a │ │ ├── 7 │ │ ├── 6 │ │ │ └── 76b07e40f24cce093536731477540f12e7da3cb6 │ │ └── e │ │ │ └── 7e2f3abc75f745043672961086ccf8aa29b4aa46 │ │ └── index.pb └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── xp │ │ └── pro │ │ └── deeplinkdemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── detail.html │ │ └── index.html │ ├── java │ │ └── com │ │ │ └── xp │ │ │ └── pro │ │ │ └── deeplinkdemo │ │ │ ├── DeepLinkActivity.java │ │ │ ├── JsManager.java │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ ├── activity_deep_link.xml │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── xp │ └── pro │ └── deeplinkdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XieXiePro/DeeplinkDemo/7f467e02942796a88f6b17450ad8b0c5e25f6c49/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 1.8 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/sonarlint/issuestore/2/e/2e2a2e3942428376ce753cdebd1f1e8adac20864: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XieXiePro/DeeplinkDemo/7f467e02942796a88f6b17450ad8b0c5e25f6c49/.idea/sonarlint/issuestore/2/e/2e2a2e3942428376ce753cdebd1f1e8adac20864 -------------------------------------------------------------------------------- /.idea/sonarlint/issuestore/3/9/39420a7303320a28a2f4d7fde496348ac4153e0a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XieXiePro/DeeplinkDemo/7f467e02942796a88f6b17450ad8b0c5e25f6c49/.idea/sonarlint/issuestore/3/9/39420a7303320a28a2f4d7fde496348ac4153e0a -------------------------------------------------------------------------------- /.idea/sonarlint/issuestore/7/6/76b07e40f24cce093536731477540f12e7da3cb6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XieXiePro/DeeplinkDemo/7f467e02942796a88f6b17450ad8b0c5e25f6c49/.idea/sonarlint/issuestore/7/6/76b07e40f24cce093536731477540f12e7da3cb6 -------------------------------------------------------------------------------- /.idea/sonarlint/issuestore/7/e/7e2f3abc75f745043672961086ccf8aa29b4aa46: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XieXiePro/DeeplinkDemo/7f467e02942796a88f6b17450ad8b0c5e25f6c49/.idea/sonarlint/issuestore/7/e/7e2f3abc75f745043672961086ccf8aa29b4aa46 -------------------------------------------------------------------------------- /.idea/sonarlint/issuestore/index.pb: -------------------------------------------------------------------------------- 1 | 2 | Y 3 | )app/src/main/res/layout/activity_main.xml,7\6\76b07e40f24cce093536731477540f12e7da3cb6 4 | o 5 | ?app/src/main/java/com/xp/pro/deeplinkdemo/DeepLinkActivity.java,2\e\2e2a2e3942428376ce753cdebd1f1e8adac20864 6 | h 7 | 8app/src/main/java/com/xp/pro/deeplinkdemo/JsManager.java,7\e\7e2f3abc75f745043672961086ccf8aa29b4aa46 8 | k 9 | ;app/src/main/java/com/xp/pro/deeplinkdemo/MainActivity.java,3\9\39420a7303320a28a2f4d7fde496348ac4153e0a -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 使用DeepLink技术唤醒 App 2 | 3 |   移动互联时代,手机作为我们日常交流的主要媒介,搭载了许许多多的移动应用程序,这些五花八门的应用程序极大的丰富了我们的生活。目前主流移动应用程序主要有Native App和Web App两种实现形式,其中Native App具有良好的用户黏性和操作体验。本篇针对从浏览器、短信、甚至是在其他APP中唤醒Native APP的需求,帮助Native App开发者为用户提供更好的交互体验,从而建立更稳固的用户关系。 4 | 5 | ### 一、Native APP唤醒场景 6 | ###### 1、浏览器 -> 唤醒APP 7 |   用户A在手机上通过浏览器打开了某APP的M站或者官网,则引导用户打开该APP或者下载该APP。 8 | ###### 2、微信、QQ等 -> 唤醒APP 9 |   用户通过某APP分享了一条链接至微信或QQ,用户B点开该链接后,引导用户B打开该APP或者下载该APP。 10 | ###### 3、短信、邮件、二维码等-> 唤醒APP 11 |   用户A打开了某APP的推广短信,邮件或者扫描二维码等,引导用户打开该APP或者下载该APP。 12 | ###### 4、其他APP -> 唤醒APP 13 |   用户A通过第三方APP分享了一条链接至用户B,用户B点开该链接后,引导用户B打开指定APP或者下载指定APP。 14 | 15 | ### 二、那么移动平台提供了哪些唤醒APP的方法呢? 16 | 17 | 目前常见的唤醒APP方式有几种: 18 | 19 | ###### 1、URL Scheme 20 |   URL Scheme是iOS,Android平台都支持,只需要原生APP开发时注册scheme, 那么用户点击到此类链接时,会自动唤醒APP,借助于URL Router机制,则还可以跳转至指定页面。 21 |   这种方式是当前使用最广泛,也是最简单的,但是需要手机,APP支持URL Scheme。 22 |   优点: 开发成本低,绝大多数都支持,web-native协议制定也简单。 23 |   缺点: 错误处理情况因平台不同,难以统一处理,部分APP会直接跳错误页(比如Android Chrome/41,iOS中老版的Lofter);也有的停留在原页面,但弹出提示“无法打开网页”(比如iOS7);iOS8以及最新的Android Chrome/43 目前都是直接停留在当前页,不会跳出错误提示。 24 | 支持情况: iOS在实际使用中,腾讯系的微信,QQ明确禁止使用,iOS9以后Safari不再支持通过js,iframe等来触发scheme跳转,并且还加入了确认机制,使得通过js超时机制来自动唤醒APP的方式基本不可用;Android平台则各个app厂商差异很大,比如Chrome从25及以后就同Safari情况一样。 25 | ###### 2、Universal Links 26 |   在2015年的WWDC大会上,Apple推出了iOS 9的一个功能:Universal Links[通用链接](https://link.jianshu.com?t=https://developer.apple.com/library/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html#//apple_ref/doc/uid/TP40016308-CH12-SW2)。如果你的App支持Universal Links,那就可以访问HTTP/HTTPS链接直接唤起APP进入具体页面,不需要其他额外判断;如果未安装App,访问此通用链接时,可以一个自定义网页。 27 | 28 | ###### 3、Android App Links 29 |   在2015年的Google I/O大会上,Android M宣布了一个新特性:[App Links](https://link.jianshu.com?t=https://developer.android.com/training/app-links/index.html)让用户在点击一个普通web链接的时候可以打开指定APP的指定页面,前提是这个APP已经安装并且经过了验证,否则会显示一个打开确认选项的弹出框。在推动deep linking上Google和Apple可谓英雄所见略同,优缺点也大致相同,只支持Android M以上系统。 30 | 31 |   总结以上各种方案从长远趋势来看都是Deep Links技术,都需要 32 | 33 | * **一个支持HTTPS的Web站** 34 | 35 | ### 三、DeepLink相关技术和产品 36 |   目前市面移动DeepLink相关技术和产品,包括系统基础技术,巨头产品,创新产品,图示如下。 37 | 38 | ![Deep Link技术产品栈](https://upload-images.jianshu.io/upload_images/2783386-92fe1a991309d25c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 39 | 40 | ### 四、DeepLink全方位解析 41 |   所谓DeepLink(深度链接)就是支持在移动App自由跳转的技术,在PC的Web时代,这个问题简化一个HTTP地址。到了移动时代,这个问题变得复杂起来,移动操作系统有多家,各家处理应用间跳转的底层技术都不一样,调用方式、代码都不同,支持的力度也不同。目前也没有任何行业协会致力于解决这个问题,没有像W3C组织解决Web的规范化。 42 | 43 | 1,什么是deeplink?什么是applink?两者的关系和区别是什么? 44 |   deeplink是从拦截外部请求到app内并定位到具体页面的技术. 45 |   简单讲,就是你在手机上点击一个链接之后,可以直接链接到app内部的某个页面,而不是app正常打开时显示的首页。不似web,一个链接就可以直接打开web的内页,app的内页打开,必须用到deeplink技术。 46 | 47 | 2,deeplink的作用是什么? 48 |   deeplink能够将外部流量引导到app内, 并提供连贯的浏览体验, 实在是引流的大杀器. 49 |   deeplink还做高效的流量分发. 通过外部url的投放和内部拦截, 可以针对不同场景直接分发流量到具体页面, 将用户直接引导到各个垂直频道. 50 | 51 | 3,有哪些比较成熟的解决方案? 52 |   魔窗等 53 | 54 | 4,安全性如何? 55 | [Android Intent Scheme URLs攻击](http://blog.csdn.net/l173864930/article/details/36951805) 56 | ### 五、技术实现 57 | 下面以Android为例实现浏览器唤醒APP。 58 | 59 | 一)浏览器唤醒APP 60 | 1,首先创建Android工程。 61 | ![deeplink demo](https://upload-images.jianshu.io/upload_images/2783386-3c3e419d8b4c5a1d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 62 | 63 | 2,新建DeepLinkActivity,并在清单文件中配置如下: 64 | ``` 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 84 | 85 | 86 | ``` 87 | 3,网页中使用如下代码,打开app指定页面: 88 | ``` 89 | 打开详情 90 | ``` 91 | 4,在app中接收html打开原生页面请求: 92 | ``` 93 | activityDataWebview.setWebViewClient(new WebViewClient() { 94 | @Override 95 | public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { 96 | String url = request.getUrl().toString(); 97 | Uri uri = Uri.parse(url); 98 | if (uri.getScheme().equals("xp") && uri.getHost().equals("detail")) { 99 | Toast.makeText(MainActivity.this, "HTML open Android native App success!", Toast.LENGTH_LONG).show(); 100 | Intent intent = new Intent(); 101 | intent.setData(uri); 102 | startActivity(intent); 103 | } else { 104 | view.loadUrl(url); 105 | } 106 | return true; 107 | } 108 | }); 109 | ``` 110 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.1" 6 | defaultConfig { 7 | applicationId "com.xp.pro.deeplinkdemo" 8 | minSdkVersion 21 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:26.+' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | } 31 | -------------------------------------------------------------------------------- /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/xp/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/xp/pro/deeplinkdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.xp.pro.deeplinkdemo; 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.xp.pro.deeplinkdemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/assets/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 404 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 打开详情 18 |
19 | 20 |
21 | 22 | -------------------------------------------------------------------------------- /app/src/main/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 404 10 | 11 | 12 |
13 |
14 | 15 |
16 |
17 | 18 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/xp/pro/deeplinkdemo/DeepLinkActivity.java: -------------------------------------------------------------------------------- 1 | package com.xp.pro.deeplinkdemo; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.widget.Toast; 8 | 9 | public class DeepLinkActivity extends AppCompatActivity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_deep_link); 15 | 16 | Intent intent = getIntent(); 17 | if (intent != null && intent.getData() != null) { 18 | Uri uri = Uri.parse(intent.getData().toString()); 19 | Toast.makeText(DeepLinkActivity.this, uri.toString(), Toast.LENGTH_LONG).show(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/xp/pro/deeplinkdemo/JsManager.java: -------------------------------------------------------------------------------- 1 | package com.xp.pro.deeplinkdemo; 2 | import android.util.Log; 3 | import android.webkit.JavascriptInterface; 4 | 5 | public class JsManager { 6 | @JavascriptInterface 7 | public void openNative() { 8 | String url = "xp://detail"; 9 | Log.d("openNative: ",url); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/xp/pro/deeplinkdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.xp.pro.deeplinkdemo; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.webkit.JavascriptInterface; 9 | import android.webkit.WebChromeClient; 10 | import android.webkit.WebResourceRequest; 11 | import android.webkit.WebView; 12 | import android.webkit.WebViewClient; 13 | import android.widget.Button; 14 | import android.widget.Toast; 15 | 16 | public class MainActivity extends AppCompatActivity { 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_main); 22 | 23 | Button openNative = (Button) findViewById(R.id.activity_main_open_native); 24 | Button openHtml = (Button) findViewById(R.id.activity_main_open_html); 25 | Button openJs = (Button) findViewById(R.id.activity_main_js_open_native); 26 | openNative.setOnClickListener(new View.OnClickListener() { 27 | @Override 28 | public void onClick(View view) { 29 | openNativeFormNative(); 30 | } 31 | }); 32 | openHtml.setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View view) { 35 | openNativeFormHtml(); 36 | } 37 | }); 38 | openJs.setOnClickListener(new View.OnClickListener() { 39 | @Override 40 | public void onClick(View view) { 41 | openNativeFormJs(); 42 | } 43 | }); 44 | } 45 | 46 | /** 47 | * deeplink 原生启动原生页面,可支持应用内跳转及跨应用启动。 48 | */ 49 | private void openNativeFormNative() { 50 | String url = "xp://detail"; 51 | Uri uri = Uri.parse(url); 52 | Toast.makeText(MainActivity.this, "Native open Android Native App success!", Toast.LENGTH_LONG).show(); 53 | Intent intent = new Intent(); 54 | intent.setData(uri); 55 | startActivity(intent); 56 | } 57 | 58 | /** 59 | * deeplink Html启动原生页面,可支持本地html加载及服务器访问Html启动原生页面。 60 | */ 61 | private void openNativeFormHtml() { 62 | WebView activityDataWebview = (WebView) findViewById(R.id.activity_main_webview); 63 | // 设置setWebChromeClient对象 64 | activityDataWebview.setWebChromeClient(new WebChromeClient()); 65 | activityDataWebview.setWebViewClient(new WebViewClient() { 66 | @Override 67 | public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { 68 | //通过外部浏览器启动可不写此部分 69 | String url = request.getUrl().toString(); 70 | Uri uri = Uri.parse(url); 71 | if (uri.getScheme().equals("xp") && uri.getHost().equals("detail")) { 72 | Toast.makeText(MainActivity.this, "HTML open Android native App success!", Toast.LENGTH_LONG).show(); 73 | Intent intent = new Intent(); 74 | intent.setData(uri); 75 | startActivity(intent); 76 | } else { 77 | view.loadUrl(url); 78 | } 79 | return true; 80 | } 81 | }); 82 | activityDataWebview.loadUrl("file:///android_asset/detail.html"); 83 | } 84 | 85 | /** 86 | * JS方式启动原生页面,可支持html启动原生页面。 87 | */ 88 | private void openNativeFormJs() { 89 | WebView activityDataWebview = (WebView) findViewById(R.id.activity_main_webview); 90 | activityDataWebview.getSettings().setJavaScriptEnabled(true); 91 | activityDataWebview.loadUrl("file:///android_asset/index.html"); 92 | //将java中类映射到js中 jsObj为该类的一个对象名 93 | // activityDataWebview.addJavascriptInterface(this, "jsObj"); 94 | activityDataWebview.addJavascriptInterface(new JsManager(), "jsObj"); 95 | } 96 | 97 | // @JavascriptInterface 98 | // public void openNative() { 99 | // String url = "xp://detail"; 100 | // Uri uri = Uri.parse(url); 101 | // Toast.makeText(MainActivity.this, "Js open Android native App success!", Toast.LENGTH_LONG).show(); 102 | // Intent intent = new Intent(); 103 | // intent.setData(uri); 104 | // startActivity(intent); 105 | // } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_deep_link.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |