如何在Android上实现自己的URI方案

186

假如我想定义一个类似于以下 URI 的东西:

myapp://path/to/what/i/want?d=This%20is%20a%20test

必须由我的应用程序或服务处理。请注意,方案是"myapp"而不是"http""ftp"。这正是我想要的:在Android操作系统中全局定义自己的URI模式。这可能吗?

这有点类似于一些程序已经在Windows系统上执行的操作,例如Skype (skype://)或任何种子下载程序(torrent://)。


3
如何注册一个URL命名空间(myapp)以便访问你的程序(app/start)?您可以在Django项目中的URLconf中定义URL模式来实现这一点。在您的应用程序的urls.py文件中,您可以使用urlpatterns变量来定义URL模式并将其与视图函数或类绑定。例如:from django.urls import path from . import views app_name = 'myapp' urlpatterns = [ path('app/start/', views.start, name='start'), # additional URL patterns go here ]在这里,我们定义了一个名为myapp的应用程序命名空间,然后定义了一个名为start的URL模式,并将其与名为views.start的视图函数绑定。最后,我们指定了该URL模式的名称,以便在模板中引用它。在Django项目中使用应用程序命名空间时,请确保在include()函数中包含命名空间参数。例如,如果您要在Django项目的主URLconf中包含myapp应用程序的URL配置,则可以执行以下操作:from django.urls import include, path urlpatterns = [ path('myapp/', include('myapp.urls', namespace='myapp')), # additional URL patterns go here ]在这里,我们将myapp应用程序的URL配置包括在Django项目的主URLconf中,并指定命名空间为myapp。由此产生的URL将具有形式/myapp/app/start/,并且可以在模板中使用名称myapp:start进行引用。 - Casebash
5个回答

235
这是非常可能的;您可以在AndroidManifest.xml中使用<data>元素定义URI方案。您可以设置一个意图过滤器,填写<data>元素,然后就能创建自己的方案了。(更多有关意图过滤器和意图解析的信息请参阅此处。)
以下是一个简短的示例:
<activity android:name=".MyUriActivity">
    <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="path" />
    </intent-filter>
</activity>

根据隐式意图的工作方式,您需要至少定义一个操作和一个类别。在这里,我选择了 VIEW 作为操作(虽然它可以是任何内容),并确保添加了 DEFAULT 类别(因为所有隐式意图都需要此类别)。还请注意,我添加了 BROWSABLE 类别-这不是必需的,但它将允许您的 URI 可以从浏览器中打开(一个巧妙的功能)。

12
需要翻译的内容:It took me a while to figure out that to link to a specific path that the "android:path" variable has to specify everything after the protocol, ie. it must be of the form "youtube.com/myvideo"为了链接到特定路径,我花了一些时间才发现,“android:path”变量必须指定协议后的所有内容,即它必须采用“youtube.com/myvideo”的形式。 - Casebash
3
很好用,但我该如何从MyUriActivity中读取URL中给定的GET参数"d"的值? - Timo Ernst
1
对我来说不起作用 我为同一个活动设置了多个意图过滤器。 一个是主要启动器。 第二个是打开特定文件 第三个如上所述 前两个完美运行,但第三个没有。 - mohitum
1
如果有人需要,这是上面链接的英文版。请返回翻译后的文本。 - Zensaburou
1
如果使用GMAIL发送类似"<a href="myApp://path> Here</a>"(路径为任何完整的com.app.packagename)这样的URI,将无法正常工作。GMAIL会在消息正文中接收到该链接,但不会将其识别为链接。而在MS Outlook中接收到相同的电子邮件将显示该链接,并在单击时尝试打开应用程序。我正在尝试通过电子邮件向我的手机发送一个包含链接以打开我的应用程序的嵌入式链接,但卡住了。 - bob
显示剩余3条评论

73

在补充@DanielLew的答案时,要获取参数的值,您需要执行以下操作:

URI示例:myapp://path/to/what/i/want?keyOne=valueOne&keyTwo=valueTwo

在您的活动中:

Intent intent = getIntent();
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
  Uri uri = intent.getData();
  String valueOne = uri.getQueryParameter("keyOne");
  String valueTwo = uri.getQueryParameter("keyTwo");
}

1
如果链接是 http://www.host.com/directory/value,我们该如何获取 value 值? - Bugs Happen
3
没关系,我在这里找到了SO的答案:链接 - Bugs Happen
如何在代码中读取AndroidManifest.xml中的数据标签,而不使用元数据。我需要将确切的方案、路径和主机发送到服务器,并在oauth调用中使用。我不想重复回调声明! - Pradeep Chakravarti Gudipati
1
@BugsHappen 是最后一个URI路径段。使用 uri.getLastPathSegment(); - Martin

27

我强烈建议您不要定义自己的URI方案。这违反了URI方案的Web标准,这些标准试图严格控制这些名称,有充分的理由-以避免不同实体之间的名称冲突。一旦您在网站上放置一个指向您方案的链接,您就已经将那个小名称放入整个互联网的命名空间中,并应该遵循这些标准。

如果您只想要能够链接到自己的应用程序,我建议您按照我在这里描述的方法操作:

如何注册某个URL命名空间(myapp://app.start/),以通过在Android OS浏览器中调用URL来访问您的程序?


2
谢谢你提醒我,但我只会在封闭的环境中使用它来尝试证明一个概念。如果这个实验离开测试阶段,我一定会考虑批准整个交易。 - punnie
6
好的,但为什么不做正确的事呢?这并不需要更多的工作。 - hackbod
3
Youtube执行@hackbod的建议,但是从Facebook打开Youtube链接会打开浏览器而不是Youtube应用程序。这个机制太“微妙”了吗? - AlikElzin-kilaka
22
我倾向于定义自己的方案,这样我就可以使用相同的网络逻辑来启动我的iOS应用程序或Android应用程序。这只是我的个人看法。 - Chicowitz
2
@hackbod 我认为当他们撰写那个rfc时,并没有考虑到android。虽然我完全同意你不需要创建新的scheme,但我认为原因正是如此:甚至不需要创建新的scheme就可以达到目标。 现在,当你像Facebook、WhatsApp或其他大型、成熟的技术工具一样时,“不创建新的URI-Scheme”规则当然不再适用于你。当你的名字已经与全球公司联系在一起时,方案名称不会发生冲突。 - icyerasor

8
由于这个问题是几年前提出的,Android在URI方案上已经有了很大的进展。从最初的URI方案到深层链接再到现在的Android应用链接。
现在Android建议使用HTTP URL而不是定义自己的URI方案。因为Android应用链接使用指向您拥有的网站域名的HTTP URL,因此没有其他应用程序可以使用您的链接。您可以从这里了解深层链接和Android应用链接的比较。
现在,您可以通过使用Android Studio选项“工具>应用链接助手”轻松地添加URI方案。请参考Android文档的详细信息:https://developer.android.com/studio/write/app-link-indexing.html

7

另一种实现Diego方案的替代方法是使用一个库:

https://github.com/airbnb/DeepLinkDispatch

您可以通过在Activity上的注释来轻松声明您想要处理的URI和提取的参数,例如:
@DeepLink("path/to/what/i/want")
public class SomeActivity extends Activity {
  ...
}

作为额外的好处,查询参数也将传递给Activity。

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