天天看點

IOS - 使用Linking處理APP被外部URL調起的事件和解析URL參數

參考資料:

https://blog.csdn.net/sinat_17775997/article/details/70473988

https://www.jianshu.com/p/8f2232da0956

http://www.cocoachina.com/ios/20161026/17855.html

本文主要介紹react-native應用如何處理APP被外部URL調起的事件,并解析URL攜帶的參數。

1、應用間互相跳轉簡介

在iOS開發的過程中,我們經常會遇到需要從一個應用程式A跳轉到另一個應用程式B的場景。這就需要我們掌握iOS應用程式之間的互相跳轉知識。

2、應用間互相跳轉實作原理

在iOS中打開一個應用程式隻需要拿到這個應用程式的協定頭即可,是以我們隻需配置應用程式的協定頭即可。

假設有應用A和應用B兩個應用,現在需要從應用A跳轉到應用B中。

原理:通過設定跳轉到應用B的URL Schemes(自定義的協定頭),應用B将其自身“綁定”到一個自定義URL Schemes上,就可以從應用A中利用應用B的URL Schemes啟動應用B了。

IOS應用在info.plist檔案中可以設定URL Schemes(URL types -> URL Schemes)。

(APP可以向手機作業系統注冊一個 URL scheme,該 scheme 用于從浏覽器或其他應用中啟動本應用。)

IOS - 使用Linking處理APP被外部URL調起的事件和解析URL參數

3、RN端使用Linking處理APP被其注冊過的外部 url 調起的情況

這一步,需要考慮兩種情況,即

(1)APP未在運作

當APP未在運作狀态時,可以使用Linking.getInitialURL()方法來處理外部URL調起的事件。

(2)APP在運作當中

當APP處在運作狀态時,Linking.getInitialURL()方法是不會響應外部URL調起事件的。需要執行以下操作:

IOS - 使用Linking處理APP被外部URL調起的事件和解析URL參數

首先,是在IOS原生端添加上述代碼,這段代碼的作用是當APP在運作當中被外部URL調起時,往RN端發送事件。這樣RN端的Linking子產品就能響應事件了。

然後,RN端就可以監聽LinKing的相關事件了。

IOS - 使用Linking處理APP被外部URL調起的事件和解析URL參數

樣例代碼如下:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    Linking,
    TouchableHighlight,
    View,
    ScrollView
} from 'react-native';


import PropTypes from 'prop-types';


class CustomButton extends Component {

    constructor(props) {
        super(props);
    }

    static propTypes = {
        url: PropTypes.string,
        text: PropTypes.string.isRequired,

    };

    render() {
        return (
            <TouchableHighlight
                style={styles.button}
                underlayColor="#a5a5a5"
                onPress={() => Linking.canOpenURL(this.props.url).then(supported => {
                    if (supported) {
                        Linking.openURL(this.props.url);
                    } else {
                        console.log('無法打開該URI: ' + this.props.url);
                    }
                })}>
                <Text style={styles.buttonText}>{this.props.text}</Text>
            </TouchableHighlight>
        );
    }
}

export default class IOSLinkingDemo extends Component {

    constructor(props) {
        super(props);
        this.state = {
            url: '',
            params: ''
        };
    }

    componentDidMount() {
        //Linking.getInitialURL():APP在運作當中,這個方法是不能處理APP被外部URL調起的情況的。
        Linking.getInitialURL().then((url) => {
            this.handleUrl(url);
        }).catch(err => {
            console.error('錯誤資訊為:', err);
            alert('錯誤資訊為:' + err);
        });
        //要在 App 啟動後也監聽傳入的 App 連結
        Linking.addEventListener('url', this._handleOpenURL);
    }

    componentWillMount() {
        Linking.removeEventListener('url', this._handleOpenURL);
    }

    _handleOpenURL = (event) => {
        this.handleUrl(event.url);
    };

    // 取URL位址參數轉為對象
    handleUrl = (url) => {
        if (url) {
            console.log('捕捉的URL位址為: ' + url);
            alert('捕捉的URL位址為: ' + url);
            let urlObj = this.getUrlParamsToJSON(url);
            let params = '';
            if (urlObj) {
                for (let key in urlObj) {
                    params = params + `${key}=${urlObj[key]}\n`;
                }
                this.setState({
                    params: params
                });
            }

        } else {
            console.log('url為空');
            alert('url為空');
        }
    };


    getUrlParamsToJSON = (url) => {
        var params = {};
        //去除所有空格
        url = url.replace(/\s/ig, '');
        //正規表達式比對
        url.replace(/([^?&=]+)=([^&]+)/g, (_, key, value) => {
            params[key] = value;
        });
        return params;
    };


    /**
     * 擷取URL的查詢參數
     */
    getUrlParamsToMap = (url) => {
        var params = new Map();
        //去除所有空格
        url = url.replace(/\s/ig, '');
        //正規表達式比對
        url.replace(/([^?&=]+)=([^&]+)/g, (_, key, value) => {
            params.set(key, value);
        });
        return params;
    };


    render() {
        return (
            <ScrollView style={{flex: 1}}>
                {/*<CustomButton url={'http://www.reactnative.vip'} text="點選打開http網頁"/>*/}
                {/*<CustomButton url={'https://www.baidu.com'} text="點選打開https網頁"/>*/}
                {/*<CustomButton url={'smsto:13667377378'} text="點選進行發送短信"/>*/}
                {/*<CustomButton url={'tel:13667377378'} text="點選進行打電話"/>*/}
                {/*<CustomButton url={'mailto:[email protected]'} text="點選進行發郵件"/>*/}
                {/*<CustomButton url={'dfy:888999'} text="無法打開url"/>*/}
                {/*<CustomButton url={'geo:37.484847,-122.148386'} text="點選打開一個地圖位置"/>*/}
                {/*<CustomButton url={'myrnlinkdemo://'} text="自己打開自己"/>*/}
                <CustomButton url={'myrnlinkdemo1://'} text="打開myrnlindemo1"/>
                <Text>
                    url參數:{this.state.params}
                </Text>
            </ScrollView>
        );
    }
}

const styles = StyleSheet.create({
    button: {
        margin: 5,
        backgroundColor: 'white',
        padding: 15,
        borderBottomWidth: StyleSheet.hairlineWidth,
        borderBottomColor: '#cdcdcd',
    },
    buttonText: {
        fontSize: 20,
    },
});
           

4、從 Safari 中調用自定義 URL Schemes

在 Xcode 中運作應用,一旦應用被安裝,自定義 URL scheme 就會被注冊,通過模拟器關閉應用,啟動 Safari 在浏覽器位址欄輸入之前定義的 URL scheme(如下):

圖中設定的URL Schemes為myrnlinkdemo,是以在浏覽器當中輸入:myrnlindemo://index?page=index。

IOS - 使用Linking處理APP被外部URL調起的事件和解析URL參數
IOS - 使用Linking處理APP被外部URL調起的事件和解析URL參數
IOS - 使用Linking處理APP被外部URL調起的事件和解析URL參數

5、在RN端可以利用URL傳遞進來的參數進行自定義處理。

當APP拿到參數對象後,就可以根據自己的業務需求進行自定義處理。比如傳遞過來page參數為index,就跳轉到首頁,如果page為其他參數,就跳轉到其他頁面,以此類推。