H5在浏览器跳转到App

  1. 配置URL Schemes
IOS Info.plist
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>xxxx</string>
        </array>
    </dict>
</array>

Android AndroidManifest.xml
<intent-filter>
   <data android:scheme="xxxx" android:host="com.aaa.bbb" />
   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.DEFAULT" />
   <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
  1. h5跳转
    通过window.location.href = xxxxx的方式跳转
const openApp = (isIOS, extinfo?: string) => {
    if (isIOS) {
        // link 就是 window.location.href = xxxxx;
        link(`xxxx://${extinfo || ""}`);
    } else {
        link(`xxxx://com.aaa.bbb/${extinfo || ""}`);
    }
};
  1. 跳转失败打开应用市场
    是没法知道有没有跳转App成功的,设置定时器3秒以后跳转应用市场
const open = () => {
    openApp(isIOS);
    window.addEventListener("visibilitychange", () => {
        const hidden = window.document.hidden || window.document["mozHidden"] || window.document["msHidden"] || window.document["webkitHidden"];
        if (!hidden) {
            window.timer && clearTimeout(window.timer); 
        }
    });
    window.timer && clearTimeout(window.timer);
    window.timer = setTimeout(() => {
        // 打开市场
        // IOS 跳 AppStore https://itunes.apple.com/us/app/idxxxxxxxxxx
        // Android 可以根据品牌 比如小米 mimarket://details?id=com.aaa.bbb,还可以跳应用宝 https://sj.qq.com/appdetail/com.aaa.bbb
        openMarket();
    }, 3000);
};

微信内H5拉起App

https://open.weixin.qq.com/
wx-open-launch-app

Web

验证微信Api

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [
        "updateAppMessageShareData",
        "updateTimelineShareData",
    ], // 必填,需要使用的JS接口列表
    openTagList: [
        'wx-open-launch-weapp',
        'wx-open-launch-app'
    ], // 可选,需要使用的开放标签列表
});
import React from "react";

const LaunchApp: React.FC<{
    appid: string;
    onError?: () => void;
    extinfo?: string;

}> = (props) => {
    const launchApp = React.useRef<any>();
    const functions = React.useRef<any>({});
    
    ...
    React.useEffect(() => {
        if (launchApp.current) {
            if (functions.current.error) {
                // "launch" 是拉起App成功
                launchApp.current.removeEventListener("error", functions.current.error);
            }
            functions.current = {
                ...functions.current,
                error: (x) => {
                    // 打开失败 跳转应用市场
                    props.onError && props.onError();
                }
            };
            launchApp.current.addEventListener("error", functions.current.error);
        }
        return () => {
            if (launchApp.current && functions.current.error) {
                launchApp.current.removeEventListener("error", functions.current.error);
            }
        };
    }, [
        props.onError
    ]);
    
    
    return <wx-open-launch-app
        ref={launchApp}
        id="launch-btn"
        appid={props.appid}
        extinfo={props.extinfo}
        style={{
            position: "absolute",
            width: '100%',
            height: '100%',
            left: 0,
            top: 0,
            bottom: 0,
            right: 0,
            zIndex: 9999
        }}
    >
        <script type="text/wxtag-template">
            <div style={{
                position: "absolute",
                width: '100%',
                height: '100%',
                top: 0,
                left: 0,
                zIndex: 1
            }}>
            
            </div>
        </script>
    </wx-open-launch-app>;
};

export default LaunchApp;

Android

  1. AndroidManifest
在AndroidManifest.xml添加
<activity
   android:name=".wxapi.WXEntryActivity"
   android:label="@string/app_name"
   android:theme="@android:style/Theme.Translucent.NoTitleBar"
   android:exported="true"
   android:taskAffinity="com.aaa.bbb"
   android:launchMode="singleTask">
</activity>
  1. WeChatCallback
package com.aaa.bbb.wxapi;

public interface WeChatCallback {
    void onResult();
}
  1. WeChatModule.java(initDeepLinksetDeepLinkCallback
在WeChatModule.java 写setDeepLinkCallback和initDeepLink
...
import com.facebook.react.bridge.Callback;
import com.aaa.bbb.wxapi.WeChatCallback;
...
public static Callback linkCallback = null;
public static WeChatCallback linkCacheCallback = null;
...

...
// 回调
@ReactMethod
private void setDeepLinkCallback(Callback cb) {
    WeChatModule.linkCallback = cb;
}

// 等到App加载完成后处理冷启动
@ReactMethod
private void initDeepLink() {
    if (WeChatModule.linkCacheCallback == null) {
        Log.e("wxLog:H5打开", "非冷启动");
    }  else {
        WeChatModule.linkCacheCallback.onResult();
    }
}
...
  1. WXEntryActivity.java
package com.aaa.bbb.wxapi;

...
import com.aaa.bbb.wxapi.WeChatModule;  // <=
import com.aaa.bbb.wxapi.WeChatCallback;  // <=
import com.aaa.bbb.MainActivity; // <=
...

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
    private static final String TAG = "WXEntryActivity";
    private IWXAPI api;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 判断是否是冷启动
        if (WeChatModule.modules.isEmpty()){
            Intent intent = new Intent(WXEntryActivity.this, MainActivity.class);
            startActivity(intent);
            // 冷启动延迟推送微信参数
            WeChatModule.linkCacheCallback = new WeChatCallback() {
                @Override
                public void onResult() {
                    // 处理结果
                    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
                    scheduler.schedule(() -> {
                        __start();
                        scheduler.shutdown();
                    }, 2, TimeUnit.SECONDS);
                }
            };
        } else{
            __start();
        }
        finish();
    }

    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }

    @Override
    public void onReq(BaseReq baseReq) {
        WritableMap map = Arguments.createMap();
        if (baseReq.getType() == ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX) {
            // 处理参数
            ShowMessageFromWX.Req req = (ShowMessageFromWX.Req) baseReq;
            map.putString("type", "WX_OPEN.Resp");
            map.putString("extinfo", req.message.messageExt);
            WeChatModule.linkCallback.invoke(map);
        } else {
            ...
        }
    }
    ...
    private void __start() {
        api = WXAPIFactory.createWXAPI(this, Const.APP_ID);
        api.handleIntent(getIntent(), this);
    }
}

IOS

React Native Linking

  1. GlobalManager设置全局变量用来判断是否是冷启动
 // GlobalManager.h
 #import <Foundation/Foundation.h>

 @interface GlobalManager : NSObject

 @property (nonatomic, assign) BOOL skipCold;
 + (instancetype)sharedManager;

 @end
 // GlobalManager.m
 #import "GlobalManager.h"

 @implementation GlobalManager

 + (instancetype)sharedManager {
     static GlobalManager *sharedManager = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         sharedManager = [[self alloc] init];
     });
     return sharedManager;
 }

 - (instancetype)init {
     self = [super init];
     if (self) {
         _skipCold = NO;
     }
     return self;
 }

 @end
  1. WeChatLib.m(initDeepLink)
// skipCold = YES 表示初始化完成了,可以跳过冷启动判断
RCT_EXPORT_METHOD(initDeepLink){
    [GlobalManager sharedManager].skipCold = YES;
}
  1. WeChatLib.m(onReq)
-(void) onReq:(BaseReq*)req
{
    if ([req isKindOfClass:[LaunchFromWXReq class]]) {
        LaunchFromWXReq *launchReq = req;
        NSString *appParameter = launchReq.message.messageExt;
        NSMutableDictionary *body = @{@"errCode":@0}.mutableCopy;
        body[@"type"] = @"LaunchFromWX.Req";
        body[@"extMsg"] = appParameter;
        ...
        [self sendEventName:RCTWXEventNameWeChatReq body:body];
    }
}
  1. AppDelegate.m
 #import "WeChatLib.h"
 #import "GlobalManager.h"

 - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary*)options {
   ...
   // RCTWXAppID是appid
   if ([url.scheme isEqualToString:RCTWXAppID]){
       微信支付
       if ([url.host isEqualToString:@"pay"]){
           return [WXApi handleOpenURL:url delegate:[WeChatLib sharedInstance]];
       }
       BOOL skipCold = [GlobalManager sharedManager].skipCold;
       if (skipCold) {
           不是冷启动
           [RCTLinkingManager application:app openURL:url options:options];
       } else {
           是冷启动 3秒以后再执行
           [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(timerFired:) userInfo:@{
                   @"url": url,
                   @"app": app,
                   @"options": options
               } repeats:NO];
           };
       }
       return [WXApi handleOpenURL:url delegate:self];
   }
   return [RCTLinkingManager application:app openURL:url options:options];
 }

 - (void)timerFired:(NSTimer *)timer {
       NSDictionary *userInfo = timer.userInfo;
       NSURL *url = userInfo[@"url"];
       UIApplication *app = userInfo[@"app"];
       NSDictionary *options = userInfo[@"options"];
       [RCTLinkingManager application:app openURL:url options:options];
 }

React Native

// 获取参数路由跳转或者其他操作
const open = (e?: {path?: string; params?: any}) => {
    if (e && e.path) {
        navigator.push(e.path, e.params);
    }
};
// import {NativeModules, Platform, NativeEventEmitter} from 'react-native';
// import {Linking} from 'react-native';
const SCHEMES_ANDROID = "xxxx://com.aaa.bbb/";
const SCHEMES_IOS = "xxxx://";
const WeChatModule = NativeModules.WeChatModule;
const nativeEventEmitter = new NativeEventEmitter(WeChatModule);

// 注册微信
WeChatModule.registerApp(
    "appid",
    "universalLink",
).then((err) => {
    if(!err && Platform.OS === 'android'){
        // 监听Android微信获取参数
        getWxAndroidDeepLink();
    }
});

// 监听IOS微信获取参数
nativeEventEmitter.addListener("WeChat_Req", (resp) => {
    if (resp.type === "LaunchFromWX.Req" && Platform.OS === 'ios') {
        const [path] = resp.extMsg.split("?");
        const params = resp.extMsg ? queryStringToParams(resp.extMsg) : {};
        open({path, params});
    }
    ...
});

// 监听Android微信获取参数
function getWxAndroidDeepLink () {
    WeChatModule.setDeepLinkCallback((e) => {
        if (e && e.type === "WX_OPEN.Resp" && e.extinfo) {
            const [path] = e.extinfo.split("?");
            const params = e.extinfo ? queryStringToParams(e.extinfo) : {};
            open({path, params});
        }
        getWxAndroidDeepLink();
    });
}


// 获取来自浏览器跳转带来的参数
const getDeepLinkFromWeb = (options?: {url?: string}) => {
    if (options && options.url) {
        const SCHEME = Platform.OS === "android" ? SCHEMES_ANDROID : SCHEMES_IOS;
        if (options.url.match(SCHEME)) {
            const url = options.url.replace(SCHEME, "");
            const [path] = url.split("?");
            // 字符串转化为params对象
            const params = queryStringToParams(url);
            open({path, params});
        }        
    }
};
// 初始化(监听浏览器获取参数)
const initRouteFromWeb = () => {
    Linking.getInitialURL().then((url) => {
        getDeepLinkFromWeb({url});
        //初始化微信
        WeChatModule.initDeepLink();
        Linking.addEventListener("url", getDeepLinkFromWeb);
    });
};

百度App


perkz
51 声望28 粉丝