GithubHelp home page GithubHelp logo

jawidx / web-launch-app Goto Github PK

View Code? Open in Web Editor NEW
763.0 20.0 104.0 951 KB

🔥 launch app from web page(调起app、调用端能力、下载app、环境判断、复制)

License: MIT License

JavaScript 54.00% TypeScript 46.00%
scheme universallink applink download appstore invoke intent launch launchapp callapp

web-launch-app's Introduction

web-launch-app

Intro

  • 唤起App到指定页、通过Scheme调用端能力、下载安装包、到应用商店,同时提供了相关的detector、copy、util等功能

Install

Usage

import {
    LaunchApp, detector, ua, copy, supportLink,
    isAndroid, isIos, inWeixin, inQQ, inWeibo, inBaidu
} from 'web-launch-app';

const lanchApp = new LaunchApp(config);
// 简单唤起
lanchApp.open({
    page: 'pagename/action',
    param:{
        k: 'v'
    }
});

// 复杂唤起
lanchApp.open({
    useYingyongbao: inWeixin && isAndroid,
    launchType: {
        ios: inWeixin ? 'store' : 'link',
        android: inWeixin ? 'store' : 'scheme',
    },
    autodemotion: false,
    scheme: 'app://path?k=v',
    url: 'https://link.domain.com/path?k=v',
    param:{
        k2: 'v2'
    },
    timeout: 2000,
    pkgs:{
        android: 'https://cdn.app.com/package/app20190501.apk',
        ios: 'https://itunes.apple.com/cn/app/appid123?mt=8',
        yyb: 'http://a.app.qq.com/o/simple.jsp?pkgname=com.app.www&ckey=CK123'
    }
}, (s, d, url) => {
        console.log('callbackout', s, d, url);
        s != 1 && copy(url);
        return 2;
    });

// 下载
lanchApp.download();
lanchApp.download({
    android: 'https://cdn.app.com/package/app20190501.apk',
    ios: 'https://itunes.apple.com/cn/app/appid123?mt=8',
    yyb: 'http://a.app.qq.com/o/simple.jsp?pkgname=com.app.www&ckey=CK123',
    landPage: 'https://haokan.baidu.com/download'
});

API

export

  • LaunchApp:唤起类,核心逻辑所在,提供了open()及download()方法通过不同方案实现唤起App及下载
  • copy:复制方法(浏览器安全限制,必须由用户行为触发)
  • detector:宿主环境对象(含os及browser信息)
  • ua:= navigator.userAgent + " " + navigator.appVersion + " " + navigator.vendor
  • isAndroid、isIos、inWeixin、inQQ、inWeibo、inBaidu:字面含义,Boolea值
  • supportLink:当前环境是否支持universal link或applink

open(options, callback)

Param Notes
options useGuideMethod 是否使用引导提示,优先级高于launchType指定的方案(适用于微信、微博等受限环境),默认false
guideMethod 引导提示方法,默认蒙层文案提示
updateTipMethod 版本升级提示方法,scheme配置指定版本时使用,默认alert提示
useYingyongbao launchType为store方案时(应用宝归为应用商店),控制微信中是否走应用宝,默认false
launchType 【1】link:iOS9+使用universal link,Android6+使用applink,可配置指定link无法使用时自动降级为scheme。【2】scheme:scheme协议,通过唤起超时逻辑进行未唤起处理,同时适用于app内打开页面调用native功能。【3】store:系统应用商店(去应用宝需要指定useYingyongbao为true)
autodemotion 是否支持link方案不可用时自动降级为scheme方案,(注意参数配置:使用page时要有同page下的link和scheme配置,或同时指定url及scheme参数),默认false
scheme 指定scheme
callback scheme的回调方法
url 指定link url(iOS的universal link值或Android的applink值)
page 在config中配置的页面名称或端能力名称(替代scheme和url参数方便维护)
param scheme或link的参数
paramMap 参数映射(适用于iOS与Android同scheme功能但参数名不同的情况,真实世界就是有这么多坑orz)
clipboardTxt 复制到剪贴板内容(针对未安装或环境受限等唤起中断情况使用,在打开app或下载app后可以通过剪贴板内容进行交互衔接或统计),浏览器安全限制需要用户动作触发才能生效
timeout scheme/store方案中超时时间,默认2000毫秒,<0表示不走超时逻辑
landPage 落地页面(异常或未知情况均会进入此页面)
pkgs {android:'',ios:'',yyb:'',store:{...}},指定子项会覆盖基础配置
callback (s, d, url) => { return 0;} ,launchType为scheme或store方案时默认有超时逻辑,可通过设置tmieout为负值取消或根据callback中的返回值进行超时处理。s表示唤起结果(0失败,1成功,2未知), d为detector,url为最终的scheme或link值。无返回值默认下载apk包或去appstore,1不处理,2落地页,3应用市场(百度春晚活动时引导去应用市场下载分流减压),详见LaunchApp.callbackResult

download(options)

Param Notes
options 未指定项使用实例配置中的默认值
yyb 应用宝地址,在微信中使用
android android apk包下载地址
ios appstore地址
landPage 落地页地址,非iOS/Android平台使用

Config

// 针对各种环境及方案参数有点多,需要使用者了解scheme及link本身的区别
// 虽然config中很多参数可以在使用api时指定,还是建议在实例时全局配置,减少使用api时传参
{
    inApp: false,   // 是否是app内(在app内使用了指定version的scheme会进行版本检测)
    appVersion: '', // 对具体scheme链接进行版本检测时使用
    pkgName:'', // 应用商店使用
    deeplink:{
        // 配置scheme方案具体页面及参数,生成请求格式为"protocol://path?param&param"
        scheme: {
            android: {
                // 指定android的scheme协议头
                protocol: 'appname',
                index: {    // 页面名或端能力名(默认请设置为:index)
                    protocol: 'appname', // 可选,如无会读取上一级protocol,一般不需要配置
                    path: 'path',
                    param: {},	// 生成scheme或linkurl时的固定参数
                    paramMap: {},// 参数映射,解决不同平台参数名不一至情况
                    version: '4.9.6'  // 版本要求
                },
                share:{...},
                ...
            },
            ios: {
                ...
            }
        },
        // 配置univerlink或applink方案中具体页面url及参数
        link: {
            pagename: {
                url: 'https://link.app.com/p/{forumName}',	// 支持占位符
                param: {
                },
                paramMap: {
                },
                version: 0
            },
            ...
        }
    },
    // 下载包配置
    pkgs: { 
        yyb: 'http://a.app.qq.com/o/simple.jsp?pkgname=com.baidu.haokan&ckey=',
        android: 'https://cdn.app.com/package/app-default.apk',
        ios: 'https://itunes.apple.com/cn/app/id1092031003?mt=8',
        store: {    // android手机商店匹配,一般不需要配置
            android: {
                reg: /\(.*Android.*\)/,
                scheme: 'market://details?id=packagename'
            },
            samsung: {
                reg: /\(.*Android.*(SAMSUNG|SM-|GT-).*\)/,
                scheme: 'samsungapps://ProductDetail/{id}'
            },
            ...
        }
    }, 
    useUniversalLink: supportLink(), // 默认根据环境判断
    useAppLink: supportLink(),       // 默认根据环境判断
    autodemotion: false,    // 不支持link方案时自动降级为scheme方案,默认false
    useYingyongbao: false,   // 在微信中store方案时是否走应用宝,默认false
    useGuideMethod: false,   // 使用guide方案
    guideMethod: ()=>{},  // 引导方法,默认蒙层文案提示
    updateTipMethod: ()=>{},    // scheme版本检测时升级提示
    searchPrefix: '?',  // scheme或univerlink生成请求中参数前缀,默认为"?"
    timeout: 2000,   // scheme/store方案中超时时间,默认2000毫秒,<0表示不走超时逻辑
    landPage: '',   // 兜底页
}

Demo

// -------------------------------------------------------------------
// launch-app.ts(基础文件,通过默认配置减少业务代码开发量,多模块使用建议提npm包)
// -------------------------------------------------------------------
import { 
    LaunchApp, copy, detector, ua, supportLink,
    isAndroid, isIos, inWeixin, inWeibo
} from 'web-launch-app';
const inApp = /appname(.*)/.test(ua);
const appVersion = inApp ? /appname\/(\d+(\.\d+)*)/.exec(ua)[1] : '';
const lanchIns = new LaunchApp({
    inApp: inApp,
    appVersion: appVersion,
    pkgName: 'com.app.www',
    deeplink: {
        scheme: {
            android: {
                protocol: 'app',
                index: {
                    path: '/',
                },
                frs: {
                    protocol: 'app',
                    path: 'forum/detail',
                    param: {from:'h5'},
                    paramMap: {
                        forumName: 'kw'
                    }
                }
            },
            ios: {
                protocol: 'app',
                index: {
                    path: '/',
                },
                frs: {
                    path: 'forum/detail'
                }
            }
        },
        link: {
            index: {url: 'https://link.app.com'},
            frs: {url: 'https://link.app.com/p/{forumName}'}
        },
    },
    pkgs: {
        android: 'https://cdn.app.com/package/app-defult.apk',
        ios: 'https://itunes.apple.com/app/apple-store/appid123?pt=328057&ct=MobileQQ_LXY&mt=8',
        yyb: 'http://a.app.qq.com/o/simple.jsp?pkgname=com.app.www&ckey=123',
    },
    useUniversalLink: supportLink(),
    useAppLink: supportLink(),
    autodemotion: true,
    useYingyongbao: inWeixin && isAndroid, // 2019.7.16发布iOS微信7.0.5支持ulink
    useGuideMethod: inWeibo && isAndroid, // 受限情况下使用引导方案
    timeout: 2500,
    landPage: 'http://www.app.com/download'
});

/**
 * 唤起app到指定页面
 * @param options 
 * @param callback 
 */
export function launch(options?: any, callback?: (status, detector, scheme) => number) {
    // pkgs处理
    options.pkgs = options.pkgs || {};
    if(options.param && options.param.pkg){
        options.pkgs.android = options.pkgs.android || `https://cdn.app.com/download/app-${pkg}.apk`;
    }
    if(options.param && options.param.ckey){
        options.pkgs.android = options.pkgs.android || `http://a.app.qq.com/o/simple.jsp?pkgname=com.app.www&ckey=${ckey}`;
    }
    
    // 针对scheme方案处理剪贴板口令
    if (options.clipboardTxt === undefined) {
        let paramStr = options.param ? stringtifyParams(options.param) : '';
        if (options.scheme) {
            options.clipboardTxt = '#' + options.scheme + (paramStr ? ((options.scheme.indexOf('?') > 0 ? '&' : '?') + paramStr) : '') + '#';
        } else if (options.page) {
            // schemeConfig为实例化时参数中scheme配置
            options.clipboardTxt = '#' + schemeConfig['protocol'] + '://' + schemeConfig[options.page].path + (paramStr ? '?' + paramStr : '') + '#';
        }
    }
    // TODO 处理唤起&新增统计归因、qq浏览器写入剪贴板延迟等通用性功能...
    lanchIns.open(options, callback);
}

/**
 * 唤起app到指定页面(尝试唤起场景,使用link方案,适用于不阻断用户继续去h5页体验场景)
 * @param options 
 * @param callback 
 */
export function tryLaunch(options?: any={}, callback?: (status, detector, scheme) => number) {
    options.launchType = {
        ios: 'link',
        android: 'link'
    };
    options.autodemotion = false;
    launch(options);
}

/**
 * 唤起app到指定页面(强制唤起场景,使用scheme方案)
 */
export function forceLaunch(options?: any={}, callback?: (status, detector, scheme) => number) {
    options.launchType = {
        ios: 'scheme',
        android: 'scheme'
    };
    launch(options);
}

/**
 * 唤起app到指定页面(常见场景方案,ios走link,android优先走link不支持走scheme,android微信中走应用宝)
 * @param options 
 * @param callback 
 */
export function hotLaunch(options?: any, callback?: (status, detector, scheme) => number) {
    options.useGuideMethod = isAndroid && inWeibo;
    options.launchType = {
        ios: 'link',
        android: inWeixin ? 'store' : (supportLink ? 'link' : 'scheme')
    };
    options.useYingyongbao = isAndroid && inWeixin;
    options.autodemotion = true;

    launch(options, callback);
}

/**
 * 端内H5页面调用端能力
 */
export function invoke(options: any) {
    options.launchType = {
        ios: 'scheme',
        android: 'scheme'
    };
    options.timeout = -1;
    lanchIns.open(options);
}

/**
 * 下载安装包
 * @param opt 
 */
export function download(opt) {
    // TODO 参数处理...
    lanchIns.download(opt);
}

// -------------------------------------------------------------------
// demopage.ts(业务代码部分)
// -------------------------------------------------------------------
import {launch, tryLaunch, forceLaunch, hotLaunch, invoke, download} from 'launch-app'
// 唤起(微博出引导提示,ios微信去appstore,android微信去应用宝,同时指定超时处理及下载包)
launch({
    useGuideMethod: inWeibo,
    useYingyongbao: inWeixin && isAndroid,
    launchType: {
        ios: inWeixin ? 'store' : 'link',
        android: inWeixin ? 'store' : 'scheme'
    },
    page: 'frs',
    param: {
        k: 'v',
        ckey: '123',
        pkg: '20190502',
        target: 'https://www.app.com/download',
    },
    // scheme:'',
    // url:'https://link.app.com/path',
    // guideMethod: () => {
    //     alert('请点击右上角,选择浏览器打开~');
    // },
    timeout: 2000,
    // clipboardTxt: '#key#', // launch-app中自动生成
    // pkgs: {
        // yyb: 'http://a.app.qq.com/o/simple.jsp?pkgname=com.app.www&ckey=123', // 通过ckey参数处理,不传使用默认值
        // android: 'https://cdn.app.com/package/app-20190502.apk',  // 通过pkg参数处理
        // ios: 'https://itunes.apple.com/cn/app/appid123?mt=8'    // 不传使用默认值
    // }
}, (status, detector, url) => {
    console.log('callback', status, detector, url);
    // s != 1 && copy(url);
    return 0;
});

// 尽量使用封装的tryLaunch、forceLaunch、hotLaunch、invoke方法,减少直接使用launch方法,便于扩展
tryLaunch({
    url: 'https://link.domain.com/path?k=v',
    param:{
        k2: 'v2'
    }
})
invoke({
    page:'share',
    // scheme:'app://share',
    param:{
        k:'v'
    }
});

// 下载
download();
download({
    pkgs:{
        ios: '',
        android: '',
        yyb: '',
        landPage:''
    }
});

Who use?

好看视频、百度贴吧、伙拍小视频...

web-launch-app's People

Contributors

jawidx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

web-launch-app's Issues

安卓浏览器无法二次唤起app

代码如下:

import { LaunchApp } from 'web-launch-app';
const lanchApp = new LaunchApp();
let config = {
        launchType: 'scheme',
        scheme: `...`,
        timeout: 2000
      };
lanchApp.open(config);

测试机型:小米MIX2s

系统:miui 11.0.3

浏览器:小米自带浏览器

现象:

点击唤起app后出现引导弹框是否跳转至XXapp,此时如果选择取消,在页面重新点击唤起app,没有再次出现引导弹框。刷新当前页面也无效,必须退出浏览器,重新进入该页面,才可以再次出现引导弹框。

在iframe唤起那里打了log,发现每次点击都进行了src设置,但都只有第一次可以跳转

请问,这是安卓浏览器限制的问题么?还是我的使用不当导致

是否支持deeplink的跳转?

文档中的示例:
lanchApp.open({ // 参数含义参见Api部分
scheme: 'app://path?k=v',
url: 'https://link.domain.com/path?k=v',
param:{
k2: 'v2'
}
});

想问下大佬该插件是否支持deeplink的跳转,比如taobao://fans,因为目前已经不使用universal link了。url参数如果我直接填写deeplink,则app未安装时safari会出现弹窗提示链接无效。

download 配置了项目的下载地址, 为什么还是一直跳到好看视频

`
const lanchApp = new LaunchApp();

lanchApp.download({

    pkgs: {

      ios: 'https://itunes.apple.com/cn/app/%E4%BA%9%A6%E9%99%A2/id123123121',

      android: 'http://mytttt.cn/download-page/app/myApp-v3.1.5-release-20191011-170945_2019-10-12_14-04-15_legu_aligned_signed.apk',

      landPage: 'http://mytttt.cn/download-page/'
    }
  })`
  1. 配置了项目的下载地址, 为什么还是一直跳到好看视频,
    地址是对的, 原本直接用window.location.href 是可以跳转的
  2. 在电脑打开, 点击下载没反应, 不是应该会跳到landPage?

页面加载执行代码唤起失败,手动触发就成功

如果把代码写在页面加载时自动触发逻辑里,就会唤起APP失败。
比如VUE的mounted或者里面加一个setTimeOut这种。

但是如果把同样的代码写到按钮,人工手动点击就会成功拉起APP。

想问下又遇到这种情况吗?

open的时候callback回调为啥没有调用

// 复杂唤起
lanchApp.open(
{
useYingyongbao: inWeixin && isAndroid,
launchType: {
ios: inWeixin ? "store" : "link",
android: inWeixin ? "store" : "scheme",
},
autodemotion: false,
scheme: "app://path?k=v",
url: "https://xtaobao.com",
param: {
k2: "v2",
},
timeout: 2000,
pkgs: {
android: "https://cdn.app.com/package/app20190501.apk",
ios: "https://itunes.apple.com/cn/app/appid123?mt=8",
yyb: "http://a.app.qq.com/o/simple.jsp?pkgname=com.app.www&ckey=CK123",
},
},
(s, d, url) => {
alert("====");
console.log("callbackout", s, d, url);
s != 1 && copy(url);
return 2;
}
);

请问有详细的用法吗

你好。 有没有详细的例子? 比如直接运行,手机能打开微信? 我直接es6 语言引用包,发现并不能运行。这个运行环境是什么?

你好!有个问题,望指点!

感谢作者能够开源此代码,让我在工作中省去了很多时间。奈何能力有限,在ios中有个小问题不知道咋回事,在 ios 浏览器打开时候 先弹出了 Safari打不开该网页,因为网址无效 ,然后再进入下载页。
我用的 ios 和 安卓 打开模式都是 scheme
@web-launch-app:”^2.1.9“
大致配置如下
const schemeConfig = { android: { protocol: 'astroapp://splash_android', index: { path: '/', }, }, ios: { protocol: 'astro://', index: { path: '/' }, } } const lanchApp = new LaunchApp({ inApp: inApp, appVersion: appVersion, pkgName: '', deeplink: { scheme: schemeConfig }, pkgs: { android: 'https://xxx', ios: 'https://xxx', yyb: '', }, useUniversalLink: supportLink, useAppLink: supportLink, autodemotion: true, useYingyongbao: inWeixin, useGuideMethod: inWeixin, // 受限情况下使用引导方案 landPage: '/' })

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.