【问题标题】:Android / iOS - Custom URI / Protocol HandlingAndroid / iOS - 自定义 URI / 协议处理
【发布时间】:2012-07-10 09:15:53
【问题描述】:

有没有办法在 Android iOS 中定义某种处理机制,让我能够拦截以下任一情况:

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

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

我也希望这些可以尽可能在系统范围内。我想这在 iOS 上将是一个更大的问题,但理想情况下,我可以从任何应用程序中单击这两个方案中的任何一个,作为超链接。 Gmail、Safari 等。

【问题讨论】:

    标签: android ios protocols manifest custom-url-protocol


    【解决方案1】:

    编辑 5/2014,因为这似乎是一个受欢迎的问题,我在答案中添加了很多细节:

    安卓:

    对于 Android,请参阅Intent Filter to Launch My Activity when custom URI is clicked

    您使用意图过滤器:

    <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 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>
    

    然后,在您的活动中,如果未运行,活动将使用 Intent 中传递的 URI 启动。

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

    如果已经运行,onNewIntent() 将在您的活动中被调用,再次使用意图中的 URI。

    最后,如果您想处理原生应用中托管的 UIWebView 中的自定义协议,您可以使用:

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

    iOS:

    对于 iOS,请参阅Lauching App with URL (via UIApplicationDelegate's handleOpenURL) working under iOS 4, but not under 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"]) 
        {
          ...
        }
      }
    }
    

    }

    对于 WKWebView (iOS8+),您可以改用 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);
    }
    

    【讨论】:

    • 我发现 GMail(iOS 应用、Android 应用、网络)会从电子邮件中删除非标准链接。
    • @dzeikei 我们使用重定向到我们的自定义应用程序 URL 的 Web URL。作为奖励,我们可以更轻松地将其与我们的网络/电子邮件分析联系起来。
    • @JasonDenizac 是的,这也是我们必须做的,但如果您可以避免通过浏览器,这将是一个更好的用户体验 :)
    【解决方案2】:

    更新:这是一个非常古老的问题,iOS 和 Android 上的情况都发生了很大变化。我将在下面留下原始答案,但是任何从事新项目或更新旧项目的人都应该考虑使用deep links,这两个平台都支持。

    在 iOS 上,深层链接称为 universal links。您需要在您的网站上创建一个 JSON 文件,将您的应用与指向您网站部分的 URL 相关联。接下来,更新您的应用程序以接受 NSUserActivity 对象并设置应用程序以显示与给定 URL 对应的内容。您还需要向应用程序添加一项权利,列出应用程序可以处理的 URL。在使用中,操作系统会负责从您的站点下载关联文件,并在有人尝试打开您的应用处理的 URL 之一时启动您的应用。

    设置app links on Android 的工作方式类似。首先,您将在您的网站和您的应用程序之间建立关联,然后您将添加intent filters,让您的应用程序拦截打开您的应用程序可以处理的 URL 的尝试。

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


    原答案:

    对于 iOS,是的,您可以做两件事:

    1. 让您的应用宣传它可以处理具有给定方案的 URL。

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

    第一个选项非常简单,在Implementing Custom URL Schemes 中进行了描述。要让系统知道您的应用可以处理给定的方案:

    • 使用 CFBundleURLTypes 条目更新应用的 Info.plist

    • 在您的应用委托中实现 -application:didFinishLaunchingWithOptions:

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

    • 创建您自己的NSURLProtocol 子类。

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

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

    • 覆盖 -startLoading-stopLoading 以分别开始和停止加载请求。

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

    对于它的价值,这正是 PhoneGap 在 iOS 上的工作方式。 PhoneGap 包含一个名为 PGURLProtocol 的 NSURLProtocol 子类,它查看应用程序尝试加载的任何 URL 的方案,并在它是它识别的方案之一时接管。 PhoneGap 的开源表亲是Cordova——你可能会发现看看会有所帮助。

    【讨论】:

    • 接受的答案应该真正解决整个问题。您的回答没有提到Android。这个问题有一个粗体的“和”。
    • 这个问题真的应该分成两个问题 - 没有任何一种方法可以跨两个平台处理自定义 URI。
    【解决方案3】:

    对于您问题中的第二个选项:

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

    iOS 9 引入了一种新技术,称为通用链接,它允许您拦截指向您网站的链接,如果它们是 https://

    https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-30
      • 1970-01-01
      • 1970-01-01
      • 2020-02-09
      • 2013-04-28
      • 1970-01-01
      • 2011-10-28
      相关资源
      最近更新 更多