Android / iOS - 自定义URI / 协议处理

52

有没有一种在AndroidiOS中定义某种处理机制的方法,使我可以拦截以下任意一项:

myapp:///events/3/
- or -
http://myapp.com/events/3/

我想要“监听”协议或主机,并打开相应的Activity / ViewController。

如果可能的话,我希望它们尽可能成为系统范围。我想象这在iOS上可能会成为更大的问题,但理想情况下,我希望能够从任何应用程序(Gmail、Safari等)中以超链接的形式单击这两个方案之一。

3个回答

79

编辑于2014年5月,由于这似乎是一个热门问题,我在答案中添加了许多细节:

Android:

对于Android,请参考当自定义URI被点击时启动我的Activity的Intent Filter

你可以使用Intent Filter:

<intent-filter>
  <action android:name="android.intent.action.VIEW" /> 
  <category android:name="android.intent.category.DEFAULT" /> 
  <category android:name="android.intent.category.BROWSABLE" /> 
  <data android:scheme="myapp" /> 
</intent-filter>

这个附加在你想要启动的Activity上。例如:

<activity android:name="com.MyCompany.MyApp.MainActivity" android:label="@string/app_name">
  <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
  <intent-filter>
      <action android:name="android.intent.action.VIEW" />
      <category android:name="android.intent.category.DEFAULT" />
      <category android:name="android.intent.category.BROWSABLE" /> 
      <data android:scheme="myapp" android:host="com.MyCompany.MyApp" />
  </intent-filter>
</activity>

然后,在您的Activity中,如果它没有正在运行,那么该Activity将使用Intent中传递的URI启动。

Intent intent = getIntent();
Uri openUri = intent.getData();

如果应用已经在运行中,在新的Intent中将再次调用您的Activity中的onNewIntent()方法,其中包含URI。

最后,如果您希望处理嵌入到原生应用程序中的UIWebView中的自定义协议,可以使用以下方法:

myWebView.setWebViewClient(new WebViewClient()
{
 public Boolean shouldOverrideUrlLoading(WebView view, String url)
 {
  // inspect the url for your protocol
 }
});

iOS:

对于iOS,请参考在iOS 4下使用NSURL启动APP,但在iOS 3.2下无法工作。通过Info.plist键定义您的URL方案,类似于:

<key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>com.yourcompany.myapp</string>
        </dict>
        <dict>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myapp</string>
            </array>
        </dict>
    </array>

然后定义一个处理函数,在您的应用程序委托中调用

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
 // parse and validate the URL
}

如果您想在您的原生应用中托管的 UIWebViews 中处理自定义协议,您可以使用 UIWebViewDelegate 方法:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
 NSURL *urlPath = [request URL];
 if (navigationType == UIWebViewNavigationTypeLinkClicked)
 {
    // inspect the [URL scheme], validate
    if ([[urlPath scheme] hasPrefix:@"myapp"]) 
    {
      ...
    }
  }
}

}

对于iOS8+中的WKWebView,你可以使用WKNavigationDelegate和这个方法:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
 NSURL *urlPath = navigationAction.request.URL;  
 if (navigationAction.navigationType == WKNavigationTypeLinkActivated)
 {
   // inspect the [URL scheme], validate
   if ([[urlPath scheme] hasPrefix:@"myapp"])
   {
    // ... handle the request
    decisionHandler(WKNavigationActionPolicyCancel);
    return;
   }
 }

 //Pass back to the decision handler
 decisionHandler(WKNavigationActionPolicyAllow);
}

1
我发现的一件事是,GMail(iOS应用程序、Android应用程序、Web)会从电子邮件中删除非标准链接。 - dzeikei
4
我们使用网络链接将其重定向到我们的自定义应用程序链接。额外的好处是,我们可以更轻松地将其与我们的网络/电子邮件分析相结合。 - Jason Suárez
1
@JasonDenizac 是的,这也是我们不得不做的,但如果您可以避免通过浏览器进行操作,那将会是更好的用户体验 :) - dzeikei

25
更新:这是一个非常古老的问题,在iOS和Android上都发生了很多变化。我会保留下原始答案,但任何正在开发新项目或更新旧项目的人,应该考虑使用深度链接,这在两个平台上都受支持。
在iOS上,深度链接被称为通用链接。您需要在您的网站上创建一个JSON文件,将您的应用与指向您网站的部分的URL相关联。接下来,更新您的应用程序以接受NSUserActivity对象,并设置应用程序以显示对应于给定URL的内容。您还需要向应用添加一个授权,列出应用程序可以处理的URL。在使用中,操作系统会负责从您的网站下载关联文件,并在有人尝试打开您的应用程序处理的URL之一时启动您的应用程序。

在安卓上设置应用链接的方法类似。首先,您需要建立您的网站和应用之间的关联,然后添加意图过滤器,让您的应用程序拦截打开您的应用程序可以处理的URL的尝试。

虽然细节显然不同,但在两个平台上的方法基本相同。它使您能够将您的应用程序插入到您的网站内容的显示中,无论哪个应用程序尝试访问该内容。


翻译后的回答:

对于iOS,你可以做两件事情:

  1. 让你的应用程序广告宣传它可以处理具有给定方案的URL。

  2. 安装协议处理程序来处理你喜欢的任何方案。

第一种选择非常简单,并在实现自定义URL方案中进行了描述。要让系统知道您的应用程序可以处理给定的方案:

  • 更新应用程序的Info.plist文件,其中包含CFBundleURLTypes条目

  • 在您的应用程序委托中实现-application:didFinishLaunchingWithOptions:方法。

第二种可能性是编写自己的协议处理程序。这仅适用于您的应用程序内部,但您可以将其与上述技术结合使用。使用上面的方法使系统为给定的URL启动您的应用程序,然后在您的应用程序中使用自定义URL协议处理程序来利用iOS的URL加载系统的功能:

  • 创建一个继承NSURLProtocol的子类。

  • 重写+canInitWithRequest: -- 通常只需查看URL方案并接受与您想要处理的方案匹配的请求,但也可以查看请求的其他方面。

  • 注册您的子类:[MyURLProtocol registerClass];

  • 重写-startLoading-stopLoading分别开始和停止加载请求。

阅读上面链接的NSURLProtocol文档以获取更多信息。这里的难度水平在很大程度上取决于您要实现的内容。iOS应用程序通常会实现自定义URL处理程序,以便其他应用程序可以进行简单的请求。实现自己的HTTP或FTP处理程序需要更多的工作。

这里提一下,PhoneGap在iOS上的工作原理正是如此。PhoneGap包含一个名为PGURLProtocol的NSURLProtocol子类,它会检查应用程序尝试加载的任何URL的方案,并在识别出其中一个方案时接管该URL。 PhoneGap的开源版本是Cordova - 你可能会发现它有帮助。

10
采纳的答案应该真正回答整个问题。你的答案没有提到Android。问题中有一个加粗的“和”。 - Marshall Davis
6
这个问题实际上应该被拆分成两个问题——在两个平台上处理自定义URI没有一个通用方法。 - Robert Watkins

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接