react-native 拉起第三方地图并传值

这个功能其实挺常用的,之前我都是用原生来写这个功能.
感觉还是用套JS 写 更通用点 这里放出源码 ,方便大家复制粘贴


image.png

这里给张图片 iOS模拟器的

本JS 会读取本机是否安装了 第三方地图 拉进行判断
如果没有安装任何地图 会显示常用的 高德 百度 腾讯 地图然后跳转到对应的 下载地址

源码:
MapLinking.js 文件

import { Linking, ActionSheetIOS, Platform } from "react-native";
import ActionSheet from "../../components/ActionSheet/index";

// 腾讯地图开发者key
let tmapKey = "";

// 下载地图app地址
const DownloadUrl = {
  android: {
    GaoDe: "http://mobile.amap.com",
    BaiDu: "http://map.baidu.com",
    // TengXun: `https://pr.map.qq.com/j/tmap/download?key=${tmapKey}`
  },
  ios: {
    GaoDe:
      "https://itunes.apple.com/cn/app/gao-tu-zhuan-ye-shou-ji-tu/id461703208?mt=8",
    BaiDu:
      "https://itunes.apple.com/cn/app/bai-du-tu-shou-ji-tu-lu-xian/id452186370?mt=8",
    // TengXun: `https://pr.map.qq.com/j/tmap/download?key=${tmapKey}`
  }
};

// 第三方地图应用Url
const openUrl = ({ startLocation, destLocation, mode, type, appName }) => {
  // 高德地图参数配置
  const GaoDeDev = type === "gcj02" ? 0 : 1; // 起终点是否偏移(0:lat 和 lon 是已经加密后的,不需要国测加密; 1:需要国测加密)
  const GaoDeT =
    mode === "drive" ? "0" : mode === "bus" ? "1" : mode === "walk" ? "2" : "3"; // 导航模式: t = 0(驾车)= 1(公交)= 2(步行)= 3(骑行)= 4(火车)= 5(长途客车)

  // 百度地图参数配置
  const BaiDuMode =
    mode === "drive"
      ? "driving"
      : mode === "bus"
      ? "transit"
      : mode === "ride"
      ? "riding"
      : "walking"; // 导航模式: 可选transit(公交)、driving(驾车)、walking(步行)和riding(骑行)
  const BaiDuCoordType = type === "gcj02" ? "gcj02" : "wgs84"; // 坐标类型,必选参数

  // 腾讯地图参数配置
  const TengXunType =
    mode === "drive"
      ? "drive"
      : mode === "bus"
      ? "bus"
      : mode === "ride"
      ? "bike"
      : "walk"; // 路线规划方式参数: 公交:bus 驾车:drive 步行:walk 骑行:bike

  // IOS系统地图配置
  const IOSDirflg = mode === "drive" ? "d" : mode === "bus" ? "r" : "w";

  if (Platform.OS === "android") {
    return [
      [
        "高德地图",
        `amapuri://route/plan/?sourceApplication=${appName}&slat=${
          startLocation.lat
        }&slon=${startLocation.lng}&sname=${startLocation.title}&dlat=${
          destLocation.lat
        }&dlon=${destLocation.lng}&dname=${
          destLocation.title
        }&dev=${GaoDeDev}&m=0&t=${GaoDeT}&rideType=elebike`
      ],
      [
        "百度地图",
        `baidumap://map/direction?origin=name:${startLocation.title}|latlng:${
          startLocation.lat
        },${startLocation.lng}&destination=name:${destLocation.title}|latlng:${
          destLocation.lat
        },${
          destLocation.lng
        }&mode=${BaiDuMode}&coord_type=${BaiDuCoordType}&src=${appName}`
      ],
      [
        "腾讯地图",
        `qqmap://map/routeplan?type=${TengXunType}&from=${
          startLocation.title
        }&fromcoord=${startLocation.lat},${startLocation.lng}&to=${
          destLocation.title
        }&tocoord=${destLocation.lat},${destLocation.lng}&referer=${tmapKey}`
      ]
    ];
  }
  return [
    [
      "高德地图",
      `iosamap://path?sourceApplication=${appName}&slat=${
        startLocation.lat
      }&slon=${startLocation.lng}&sname=${startLocation.title}&dlat=${
        destLocation.lat
      }&dlon=${destLocation.lng}&dname=${
        destLocation.title
      }&dev=${GaoDeDev}&m=0&t=${GaoDeT}&rideType=elebike`
    ],
    [
      "百度地图",
      `baidumap://map/direction?origin=name:${startLocation.title}|latlng:${
        startLocation.lat
      },${startLocation.lng}&destination=name:${destLocation.title}|latlng:${
        destLocation.lat
      },${
        destLocation.lng
      }&mode=${BaiDuMode}&coord_type=${BaiDuCoordType}&src=${appName}`
    ],
    [
      "腾讯地图",
      `qqmap://map/routeplan?type=${TengXunType}&from=${
        startLocation.title
      }&fromcoord=${startLocation.lat},${startLocation.lng}&to=${
        destLocation.title
      }&tocoord=${destLocation.lat},${destLocation.lng}&referer=${tmapKey}`
    ],
    [
      "Apple地图",
      `http://maps.apple.com/?ll=${destLocation.lat},${destLocation.lng}&q=${
        destLocation.title
      }&dirflg=${IOSDirflg}`
    ]
  ];
};

/**
 * 系统内没有任何第三方地图应用,提示推荐下载列表
 */
const downloadTip = () => {
  const obj = Platform.OS === "android" ? ActionSheet : ActionSheetIOS;
  obj.showActionSheetWithOptions(
    {
      title: "未安装任何第三方地图应用,请选择其中一个应用",
      options: ["取消", "高德地图", "百度地图","腾讯地图"],
      cancelButtonIndex: 0
    },
    buttonIndex => {
      const { GaoDe, BaiDu, TengXun } = DownloadUrl[Platform.OS];
      let url = 0;
      switch (buttonIndex) {
        case 1:
          url = GaoDe;
          break;
        case 2:
          url = BaiDu;
          break;
        case 3:
          url = TengXun;
          break;
        default:
          url = GaoDe;
      }
      Linking.canOpenURL(url).then(result => {
        if (result) {
          Linking.openURL(url);
        }
      });
    }
  );
};

/**
 * 显示已经存在的第三方地图应用
 */
const showExistApp = maps => {
  const obj = Platform.OS === "android" ? ActionSheet : ActionSheetIOS;
  const options = ["取消", ...maps.map(item => item[0])];
  obj.showActionSheetWithOptions(
    {
      title: "请选择其中一个地图应用",
      options,
      cancelButtonIndex: 0
    },
    buttonIndex => {
      if (buttonIndex !== 0) {
        Linking.openURL(maps[buttonIndex - 1][1]);
      }
    }
  );
};

/**
 * 规划路线
 */
const planRoute = ({
  startLocation = {},
  destLocation = {},
  mode = "ride",
  type = "gcj02",
  appName = "MapLinking"
}) => {
  const maps = openUrl({ startLocation, destLocation, mode, type, appName });
  const promises = maps.map(item => {
    return Linking.canOpenURL(item[1]).then((supported) => {
        if (supported) {
            // console.log("Can't handle url: " + url);
            return item;
        } else {
            return false;
        }
    })
    .catch((err) => console.error('An error occurred', err));;
  });

  Promise.all(promises)
    .then(results => {
      return maps.filter((item, index) => results[index]);
    })
    .then(choices => {
      if (!choices.length) {
        // 系统内没有任何地图,展示推荐下载列表
        downloadTip();
      } else {
        showExistApp(choices);
      }
    });
};

/**
 * 初始化值(如果想兼容腾讯地图,需要传入腾讯开发者Key)
 * 【申请地址】 https://lbs.qq.com/console/key.html
 */
const init = ({ tmapKey: refererKey = "" }) => {
  tmapKey = refererKey;
};

const MapLinking = () => {};

MapLinking.planRoute = planRoute;
MapLinking.init = init;

export default MapLinking;

ActionSheet.js 文件

import React from 'react';
import { ActionSheetIOS, Platform } from 'react-native';
import ActionSheetContainer from './ActionSheetContainer';
import RootSiblings from 'react-native-root-siblings';

let instance = null;

const ActionSheet = {
    Container: ActionSheetContainer,
    useActionSheetIOS: true,
    showActionSheetWithOptions: (config, callback) => {
        if (Platform.OS === 'ios' && ActionSheet.useActionSheetIOS) {
            ActionSheetIOS.showActionSheetWithOptions(config, callback);
            return;
        }
        if (instance) {
            return;
        }
        instance = new RootSiblings(
             {
                    instance && instance.destroy(() => {
                        instance = null;
                        setTimeout(() => {
                            callback && callback(index);
                        }, 0);
                    });
                }}
            />
        );
    },
};

export default ActionSheet;

ActionSheetContainer.js 文件

import React from 'react';
import { Dimensions, Modal, ScrollView, StyleSheet, Text, TouchableHighlight, TouchableWithoutFeedback, View } from 'react-native';
import { getSafeAreaInset, isLandscape } from './SafeArea';

export default class extends React.PureComponent {
    static defaultProps = {
        backgroundColor: 'rgba(0, 0, 0, 0.3)',
        contentBackgroundColor: '#f9f9f9',
        separatorColor: '#d7d7d7',
        fontSize: 18,
        color: '#007aff',
        titleStyle: {
            fontSize: 15,
            fontWeight: 'bold',
            color: '#8f8f8f',
        },
        messageStyle: {
            fontSize: 15,
            color: '#8f8f8f',
        },
        destructiveButtonStyle: {
            color: '#d11f1f',
        },
        cancelButtonStyle: {
            fontWeight: 'bold',
        },
        touchableUnderlayColor: '#dddddd',
        supportedOrientations: ['portrait', 'landscape'],
    };

    constructor(props) {
        super(props);
        this.onWindowChange = this._onWindowChange.bind(this);
        this.state = {
            isLandscape: isLandscape(),
        };
    }

    componentDidMount() {
        Dimensions.addEventListener('change', this.onWindowChange);
    }

    componentWillUnmount() {
        Dimensions.removeEventListener('change', this.onWindowChange);
    }

    render() {
        const { config, backgroundColor, supportedOrientations } = this.props;
        const { cancelButtonIndex } = config;
        const closeFunc = this._click.bind(this, cancelButtonIndex);
        return (
            
                
                    
                        
                    
                    {this._renderSections()}
                
            
        );
    }

    _renderSections = () => {
        const {width, height} = Dimensions.get('window');
        const inset = getSafeAreaInset();
        const { config } = this.props;
        const { title, message, options, cancelButtonIndex } = config;
        const contentStyle = {
            paddingHorizontal: 10,
            marginBottom: inset.bottom > 0 ? inset.bottom : 10,
            marginTop: this.state.isLandscape ? inset.top + 10 : inset.top + 44,
        };
        contentStyle.maxHeight = height - contentStyle.marginBottom - contentStyle.marginTop;
        if (this.state.isLandscape) {
            contentStyle.width = Math.max(width / 3, height - 10 * 2);
            contentStyle.alignSelf = 'center';
        }
        const section = [];
        let cancelView = null;
        (title || message) && section.push(this._renderTitle(title, message));
        options.forEach((item, index) => {
            const itemView = this._renderItem(item, index);
            if (index === cancelButtonIndex) {
                cancelView = itemView;
            } else {
                section.push(itemView);
            }
        });
        const sections = cancelView ? [section, cancelView] : [section];
        return (
            
                {sections.map((sectionItem, index) => {
                    const style = index > 0 ? {
                        marginTop: 9,
                    } : {};
                    return this._renderSection(sectionItem, index, style);
                })}
            
        );
    };

    _renderTitle = (title, message) => {
        const { titleStyle, messageStyle } = this.props;
        const style = {marginVertical: 6};
        return (
            
                {title && (
                    
                        {title}
                    
                )}
                {message && (
                    
                        {message}
                    
                )}
            
        );
    };

    _renderItem = (item, index) => {
        const { config, destructiveButtonStyle, cancelButtonStyle, touchableUnderlayColor, fontSize, color } = this.props;
        const { destructiveButtonIndex, cancelButtonIndex } = config;
        const isCancel = index === cancelButtonIndex;
        const isDestructive = index === destructiveButtonIndex;
        const textStyle = isCancel ? cancelButtonStyle :
            isDestructive ? destructiveButtonStyle : null;
        return (
            
                
                    
                        {item}
                    
                
            
        );
    };

    _renderSection(items, index, style) {
        const {contentBackgroundColor: backgroundColor} = this.props;
        const isArray = Array.isArray(items);
        const Component = isArray ? ScrollView : View;
        const props = isArray ? {
            bounces: false,
        } : {};
        return (
            
                {isArray ? items.map((item, innerIndex) => {
                    const views = [item];
                    if (innerIndex < items.length - 1) {
                        views.push(this._renderSeparatorLine('sepline' + innerIndex));
                    }
                    return views;
                }) : items}
            
        );
    }

    _renderSeparatorLine(key) {
        const {separatorColor: backgroundColor} = this.props;
        return (
            
        );
    }

    _click(index) {
        this.props.callback && this.props.callback(index);
    }

    _onWindowChange() {
        this.setState({isLandscape: isLandscape()});
    }
}

const styles = StyleSheet.create({
    view: {
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        opacity: 1,
    },
    touchview: {
        flex: 1,
        backgroundColor: 'transparent',
    },
    content: {
        flex: 0,
    },
    section: {
        borderRadius: 11,
        overflow: 'hidden',
    },
    seperator: {
        height: StyleSheet.hairlineWidth,
    },
    title: {
        justifyContent: 'center',
        alignItems: 'center',
        paddingVertical: 10,
    },
    button: {
        alignItems: 'center',
        justifyContent: 'center',
        paddingHorizontal: 16,
        height: 57,
    },
    buttonView: {
        justifyContent: 'center',
        alignItems: 'center',
    },
});

SafeArea.js

import { Dimensions, Platform, StatusBar } from 'react-native';

export const isIos = Platform.OS === 'ios';
export const isAndroid = Platform.OS === 'android';
export const isWeb = Platform.OS === 'web';

const {width: D_WIDTH, height: D_HEIGHT} = Dimensions.get('window');

function _compare(targetWidth, targetHeight) {
    return D_WIDTH === targetWidth && D_HEIGHT === targetHeight ||
        D_WIDTH === targetHeight && D_HEIGHT === targetWidth;
}

export const isIPhoneX = function () {
    // X + XS
    const X_WIDTH = 375;
    const X_HEIGHT = 812;
    // XR + XS Max
    const XSMAX_WIDTH = 414;
    const XSMAX_HEIGHT = 896;
    return isIos && (
        _compare(X_WIDTH, X_HEIGHT) ||
        _compare(XSMAX_WIDTH, XSMAX_HEIGHT)
    );
}();

export const isNewIPadPro = function () {
    const IPADPRO11_WIDTH = 834;
    const IPADPRO11_HEIGHT = 1194;
    const IPADPRO129_HEIGHT = 1024;
    const IPADPRO129_WIDTH = 1366;
    return isIos && (
        _compare(IPADPRO11_WIDTH, IPADPRO11_HEIGHT) ||
        _compare(IPADPRO129_WIDTH, IPADPRO129_HEIGHT)
    );
}();

export const isIPad = function () {
    if (!isIos || isIPhoneX) return false;
    const PAD_WIDTH = 768;
    const minEdge = Math.min(D_WIDTH, D_HEIGHT);
    return minEdge >= PAD_WIDTH;
}();

export function getSafeAreaInset(landscape, translucent = false) {
    if (landscape === undefined) {
        landscape = isLandscape();
    }
    const inset = (top, right, bottom, left) => ({top, right, bottom, left});
    if (isIos) {
        if (isIPhoneX) {
            return landscape ? inset(0, 44, 21, 44) : inset(44, 0, 34, 0);
        } else if (isNewIPadPro) {
            return inset(24, 0, 20, 0);
        } else if (isIPad) {
            return inset(20, 0, 0, 0);
        } else {
            return landscape ? inset(0, 0, 0, 0) : inset(20, 0, 0, 0);
        }
    } else if (isAndroid) {
        const top = translucent ? StatusBar.currentHeight : 0;
        return inset(top, 0, 0, 0);
    } else {
        return inset(0, 0, 0, 0);
    }
}

export function isLandscape() {
    const {width, height} = Dimensions.get('window');
    return width > height;
}

这里是使用:

handleChange = () => {
    // starting location info
    const startLocation = {
      lng: 106.534892,
      lat: 29.551891,
      title: '公园地址'
    };

    // end location info
    const destLocation = {
      lng: 106.27613,
      lat: 29.972084,
      title: '邮局'
    };

    MapLinking.planRoute({ startLocation, destLocation });
  };

  render() {
    return (
      
        start navigation
      
    );
  }
}

你可能感兴趣的:(react-native 拉起第三方地图并传值)