原文:https://pantao.parcmg.com/press/react-native-deep-linking-for-ios-android.html
代碼:https://github.com/pantao/react-native-deep-linking-examplejavascript
咱們生活在一個萬物兼可分享的年代,而分享的過程,幾乎最終都會分享某一個連接,那麼,做爲開發者,最常遇到的問題中應該包括如何經過一個URL地址快速的打開App,並導航至特定的頁面。html
深度連接是一項可讓一個App經過一個URL地址打開,以後導航至特定頁面或者資源,或者展現特定UI的技術,Deep 的意思是指被打開的頁面或者資源並非App的首頁,最常使用到的地方包括但遠遠不限於 Push Notification、郵件、網頁連接等。前端
其實這個技術在好久好久之前就已經存在了,鼠標點擊一下 mailto:pantao@parcmg.com 這樣的連接,系統會打開默認的郵件軟件,而後將 pantao@parcmg.com
這個郵箱填寫至收件人輸入欄裏,這就是深度連接。java
本文將從零開始建立一個應用,讓它支持經過一個如 deep-linking://articles/{ID}
這樣的 URL 打開 文章詳情 頁面,同時加載 {ID}
指定的文章,好比:deep-linking://articles/4
將打開 ID
爲 4
的文章詳情頁面。node
網頁連接是沒法打開原生應用的,若是一個用戶訪問你的網頁中的某一個資源,他的手機上面也已經安裝了你的應用,那麼,咱們要如何讓系統自動的打開應用,而後在應用中展現用戶所訪問的那一個頁面中的資源?這就是深度連接須要解決的問題。react
有兩種方式能夠實現深度連接:android
前端是最多見的方式,後者是 iOS 新提供的方式,能夠一個普通的網頁地址連接至App的特定資源。ios
本文將建立一個名爲 DeepLinkingExample
的應用,使得用戶能夠經過打開 deep-linking://home
以及 deep-linking://articles/4
分別打開 App 的首頁以及 App 中 ID 爲 4
的文章詳情頁面。git
react-native init DeepLinkingExample cd DeepLinkingExample
緊跟 TypeScript 大潮流,咱們的 App 寫將使用 TypeScript 開發。github
yarn add react-navigation react-native-gesture-handler react-native link react-native-gesture-handler
咱們將使用 react-navigation 模塊做爲 App 的導航庫。
添加 TypeScript 相關的開發依賴:
yarn add typescript tslint tslint-react tslint-config-airbnb tslint-config-prettier ts-jest react-native-typescript-transformer -D yarn add @types/jest @types/node @types/react @types/react-native @types/react-navigation @types/react-test-renderer
添加 tsconfig.json
:
{ "compilerOptions": { "target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "lib": [ /* Specify library files to be included in the compilation: */ "es2017", "dom" ], "resolveJsonModule": true, "allowJs": false, /* Allow javascript files to be compiled. */ "skipLibCheck": true, /* Skip type checking of all declaration files. */ "jsx": "react-native", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ "declaration": true, /* Generates corresponding '.d.ts' file. */ "sourceMap": true, /* Generates corresponding '.map' file. */ "outDir": "./lib", /* Redirect output structure to the directory. */ "removeComments": true, /* Do not emit comments to output. */ "noEmit": true, /* Do not emit outputs. */ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ "strictNullChecks": true, /* Enable strict null checks. */ "strictFunctionTypes": true, /* Enable strict checking of function types. */ "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ "noUnusedLocals": true, /* Report errors on unused locals. */ "noUnusedParameters": true, /* Report errors on unused parameters. */ "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ /* Module Resolution Options */ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ "paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ "*": [ "*.android", "*.ios", "*.native", "*.web", "*" ] }, "typeRoots": [ /* List of folders to include type definitions from. */ "@types", "../../@types" ], // "types": [], /* Type declaration files to be included in compilation. */ "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ /* Experimental Options */ "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */ }, "exclude": [ "node_modules", "web" ] }
添加 tslint.json
文件
{ "defaultSeverity": "warning", "extends": [ "tslint:recommended", "tslint-react", "tslint-config-airbnb", "tslint-config-prettier" ], "jsRules": {}, "rules": { "curly": false, "function-name": false, "import-name": false, "interface-name": false, "jsx-boolean-value": false, "jsx-no-multiline-js": false, "member-access": false, "no-console": [true, "debug", "dir", "log", "trace", "warn"], "no-empty-interface": false, "object-literal-sort-keys": false, "object-shorthand-properties-first": false, "semicolon": false, "strict-boolean-expressions": false, "ter-arrow-parens": false, "ter-indent": false, "variable-name": [ true, "allow-leading-underscore", "allow-pascal-case", "ban-keywords", "check-format" ], "quotemark": false }, "rulesDirectory": [] }
添加 .prettierrc
文件:
{ "parser": "typescript", "printWidth": 100, "semi": false, "singleQuote": true, "trailingComma": "all" }
在項目根目錄下建立一個 src
目錄,這個將是項目原代碼的目錄。
src/App.tsx
文件import React from 'react' import { createAppContainer, createStackNavigator } from 'react-navigation' import About from './screens/About' import Article from './screens/Article' import Home from './screens/Home' const AppNavigator = createStackNavigator( { Home: { screen: Home }, About: { screen: About, path: 'about' }, Article: { screen: Article, path: 'article/:id' }, }, { initialRouteName: 'Home', }, ) const prefix = 'deep-linking://' const App = createAppContainer(AppNavigator) const MainApp = () => <App uriPrefix={prefix} /> export default MainApp
src/screens/Home.tsx
文件import React from 'react';
src/screens/About.tsx
import React from 'react' import { StyleSheet, Text, View } from 'react-native' import { NavigationScreenComponent } from 'react-navigation' interface IProps {} interface IState {} const AboutScreen: NavigationScreenComponent<IProps, IState> = props => { return ( <View style={styles.container}> <Text style={styles.title}>About Page</Text> </View> ) } AboutScreen.navigationOptions = { title: 'About', } export default AboutScreen const styles = StyleSheet.create({ container: {}, title: {}, })
src/screens/Article.tsx
import React from 'react' import { StyleSheet, Text, View } from 'react-native' import { NavigationScreenComponent } from 'react-navigation' interface NavigationParams { id: string } const ArticleScreen: NavigationScreenComponent<NavigationParams> = ({ navigation }) => { const { params } = navigation.state return ( <View style={styles.container}> <Text style={styles.title}>Article {params ? params.id : 'No ID'}</Text> </View> ) } ArticleScreen.navigationOptions = { title: 'Article', } export default ArticleScreen const styles = StyleSheet.create({ container: {}, title: {}, })
打開 ios/DeepLinkingExample.xcodeproj
:
open ios/DeepLinkingExample.xcodeproj
點擊 Info
Tab 頁,找到 URL Types
配置,添加一項:
deep-linking
deep-linking
打開項目跟目錄下的 AppDelegate.m
文件,添加一個新的 import
:
#import "React/RCTLinkingManager.h"
而後在 @end
前面,添加如下代碼:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation]; }
至此,咱們已經完成了 iOS 的配置,運行並測試是否成功。
react-native run-ios
打開 simulator
以後,打開 Safari
瀏覽器,在地址欄中輸入:deep-linking://article/4
,你的應用將會自動打開,並同時進入到 Article
頁面。
一樣的,你還能夠在命令行工具中執行如下命令:
xcrun simctl openurl booted deep-linking://article/4
要爲Android應用也建立 External Linking,須要建立一個新的 intent
,打開 android/app/src/main/AndroidManifest.xml
,而後在 MainActivity
節點添加一個新的 intent-filter
:
<application ...> <activity android:name=".MainActivity" ...> ... <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="deep-linking" /> </intent-filter> ... </activity> </application>
Android 只須要完成上面的配置便可。
執行:
react-native run-android
打開系統瀏覽器,輸入:
deep-linking://article/4
系統會自動打開你的應用,並進入 Article 頁面
也能夠在命令行工具中使用如下命令打開:
adb shell am start -W -a android.intent.action.VIEW -d "deep-linking://article/3" com.deeplinkingexample;
點擊如下連接便可: