APP 联系方式跳转功能开发设计

853 阅读3分钟

一、目标

APP 端实现 跳转其他APP 和 唤起APP,是区别 H5 端很重要的能力, 比如直接唤起本地邮箱发送邮件, 唤起 tiktok APP ,如果没有安装进入 安装下载商店。 同时如果链接是 网页端 还需要支持浏览器打开,下面将对 ios 和 android 分别实现上述功能

二、ios 端

1、处理地址的打开

处理 h5 端发送的打开某APP的消息,传入一个对象分别取scheme url和 该 app store 的地址,判断当前app地址在本机是否安装,未安装使用配置的 appStoreUrl 打开app store 下载页面

// h5 调用 native 打开联系人app
if([message isKindOfClass:[NSString class]] && [message isEqualToString:@"sharedApplication"]) {
    NSURL *url = [NSURL URLWithString:messageData[@"url"]];
    NSURL *appStoreUrl = [NSURL URLWithString:messageData[@"appStoreUrl"]];
    NSLog(@"url appStoreUrl %@ %@", url , appStoreUrl);
    // 检查应用是否可打开
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        // 应用已安装,打开应用
        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
    } else {
        // 应用未安装,不进行任何操作或提示用户
        // 可以在这里添加你自己的逻辑
        // [self channelMessage:@"showToast" withData: @"Application not installed"];
        [[UIApplication sharedApplication] openURL:appStoreUrl options:@{} completionHandler:nil];
    }
}

设置webview 允许跳转,也可以这里拦截跳转的请求 进行设置

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    //如果是跳转一个新页面
       if (navigationAction.targetFrame == nil) {
           [webView loadRequest:navigationAction.request];
       }
    decisionHandler(WKNavigationActionPolicyAllow);
};
2、判断是否安装某个app,配置 Queried URL Schemes

apple 手机上判断是否安装了哪个APP,是需要增加查询权限的, 需要查哪个APP就增加哪个

image.png

需要跳转哪个APP 就加上哪个APP的 scheme url 前缀

3、h5端跳转使用方式

ios 跳转 facebook 如果没有使用 appStoreUrl 进入下载页

iosBridge.pubSub.publish(messageKey.sendToNative, messageKey.sharedApplication, {
    url: 'fb://profile/281216048311568',
    appStoreUrl: 'itms-apps://itunes.apple.com/app/id579523206',
});

ios 跳转 邮箱示例

iosBridge.pubSub.publish(messageKey.sendToNative, messageKey.sharedApplication, {
  url: `mailto:${email}`,
});

跳转网页

iosBridge.pubSub.publish(messageKey.sendToNative, androidBridgeMessage.sharedApplication, {
   schemeUrl: "https://www.baidu.com",
   packageName: "",
});

三、android 端实现

1、处理地址打开代码
@JavascriptInterface
fun sharedApplication(urlScheme:String) {
    // 将字符串转换为 JSONObject
    val jsonObj = JSONObject(urlScheme)
    // 从 JSONObject 中获取 schemeUrl 和 packageName
    val schemeUrl = jsonObj.getString("schemeUrl")
    val packageName = jsonObj.getString("packageName")

    // 使用获取的值
    // 例如,打印到 Logcat
    Log.d("URLScheme", "Scheme URL: $schemeUrl, Package Name: $packageName")
    val intent: Intent
    val isWebUrl = schemeUrl.startsWith("http://") || schemeUrl.startsWith("https://")
    if (isWebUrl) {
        // 网页 URL,直接打开
        intent = Intent(Intent.ACTION_VIEW)
        intent.setData(Uri.parse(schemeUrl))
        startActivity(intent)
        return;
    } else {
        // scheme URL,尝试打开应用
        intent = Intent(Intent.ACTION_VIEW)
        intent.setPackage(packageName)
        intent.setData(Uri.parse(schemeUrl))
    }

    // 尝试获取可以处理 Intent 的 Activity
    val pm = packageManager;
    val componentName = intent.resolveActivity(pm)

    if (componentName != null) {
        // 应用已安装,可以打开
        startActivity(intent)
    } else {
        val url = "https://play.google.com/store/apps/details?id=$packageName"
        startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
    }
}}

仍然是传入一个对象,当判断是 http 开头,当网页URL 打开, 如果废 http 开头地址,当app 打开, 判断本机有没有 安装该 app 是通过 packageManager 来判断的, 如果未安装 进入 google play进行下载安装

2、判断是否安装了 APP

安卓上判断是否安装某个应用是在 ANdroidManifest.xml 中通过 queries 查询特定包名来实现的,依然是用到哪个app 就声明哪个

 <queries> 
   <!-- 查询特定包名的应用 --> 
   < package android:name= "com.google.android.youtube" /> 
   < package android:name= "com.ss.android.ugc.trill" /> 
   < package android:name= "com.google.android.youtube" /> 
   < package android:name= "com.twitter.android" /> 
   < package android:name= "com.linkedin.android" /> 
   < package android:name= "com.whatsapp" /> 
   < package android:name= "org.telegram.messenger" /> 
   < package android:name= "com.discord" /> 
   < package android:name= "com.zing.zalo" /> 
   < package android:name= "com.instagram.android" /> 
   < package android:name= "com.kalodata.kalodata_android" /> 
   < package android:name= "com.google.android.gm" /> 
   < package android:name= "com.zhiliaoapp.musically" />  
   <intent> 
     <action android:name= "android.intent.action.VIEW" /> 
     <category android:name= "android.intent.category.BROWSABLE" /> 
     < data android:scheme= "http" /> 
   </intent> 
</queries>
3、h5 端跳转使用方式

下面是跳转youtobe 示例

androidBridge.pubSub.publish(androidBridgeMessage.sendToNative, androidBridgeMessage.sharedApplication, {
    schemeUrl: 'youtube://channel/UCzs4yLr71NYjClyoCClwi0A',
    packageName: 'com.google.android.youtube',
});

下面是打开 email 示例

androidBridge.pubSub.publish(androidBridgeMessage.sendToNative, androidBridgeMessage.sharedApplication, {
   schemeUrl: `mailto:${email}`,
   packageName: "com.google.android.gm",
});

跳转网页

androidBridge.pubSub.publish(androidBridgeMessage.sendToNative, androidBridgeMessage.sharedApplication, {
   schemeUrl: "https://www.baidu.com",
   packageName: "",
});

四、总结

处理app跳转打开是很常见的Native端需求, 在iOS或者Android上实现该功能大体上思路是一致的,先声明想要查询的app,这样才有能力调用端上查询能力,查询该APP是否在本机安装了,没有安装跳转到特定的商店进行下载,同时也要处理好外部网页的跳转