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

56

我想创建一个Android应用程序,以便在Android操作系统中注册(或者只是在系统启动时启动),当手机用户在Web浏览器内的特殊按钮上点击时,例如:

 <a href="myapp://mysettings">Foo</a> 

我的应用程序将通过在URL中发送的参数弹出并运行。

那么我要如何做到呢?

我需要一份带代码的教程!


1
这很可能是 https://dev59.com/a3RB5IYBdhLWcg3wv5tA 的重复内容。 - Casebash
1
这个问题在https://dev59.com/CHE95IYBdhLWcg3wHqQV#2448531有一个很好的答案。 - neu242
4个回答

58

首先,为了能够从浏览器/邮件中使用自定义方案“myapp”启动您的应用程序,请将意图过滤器设置如下。

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

为了解析链接中的查询,可以使用以下代码:myapp://someaction/?var=str&varr=string (该代码过于简单,没有错误检查。)

Intent intent = getIntent();
// check if this intent is started via custom scheme link
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
  Uri uri = intent.getData();
  // may be some test here with your custom uri
  String var = uri.getQueryParameter("var"); // "str" is set
  String varr = uri.getQueryParameter("varr"); // "string" is set
}

[编辑] 如果您使用自定义协议启动应用程序,则其中一个问题是: 其他应用程序中的 WebView 可能无法理解您的自定义协议。 这可能会导致使用自定义协议的链接在浏览器中显示 404 页面。


3
这是我在这里看到的第一个例子,其中包括如何在活动中再次获取Uri..谢谢! - Ben Clayton
处理意图的代码应该编写在哪里? - Juampa
1
@Proverbio:在您的应用程序的主活动中,在onCreate方法中。 - Paranoid Android
2
在你注册了intent-filter的活动的onCreate中,使用@Proverbio。这并不一定是主要的活动。 - Tim

49
您需要遵循W3C和类似的标准规则来处理URI,基本上意味着:不要这样做。
Android定义了一种Uri语法,用于描述通用intent。Intent中有一些方法可用于转换成和从此表示形式中获取,例如:http://developer.android.com/reference/android/content/Intent.html#toUri(int) 因此,要做到这一点,您需要使用正常的方式在清单文件中描述要处理特定组件的意图类型,尤其是在自己的命名空间(例如com.mycompany.myapp.action.DO_SOMETHING)中定义一个操作名称。然后可以创建与您的组件匹配的Intent,并使用Intent.toUri()获取其URI表示形式。这可以放入您的链接中,然后当被按下时会查找能够处理它的内容,从而找到您的应用程序。请注意,要像这样从浏览器启动应用程序,组件必须处理BROWSABLE类别。(您不需要将其放在链接中的Intent中,浏览器会自动为您添加。)
最后,您可能希望使用以下方法将Intent的包设置为您的应用程序:http://developer.android.com/reference/android/content/Intent.html#setPackage(java.lang.String) 这是平台上的一个较新功能,允许您将Intent直接链接到您的应用程序,以便其他应用程序无法截获和处理它们。
总之:请阅读有关意图和意图过滤器的常规文档(例如NotePad教程,虽然您可能不会在此处使用内容:URI,而只是自定义操作),并以此方式使您的应用程序正常工作。然后,您可以创建一个浏览器链接以相同的方式启动您的应用程序,前提是您的intent-filter处理了BROWSABLE类别。

3
起初我认为您没有解释忽略URI标准规则的坏处,但后来我在这里找到了您的其他答案 - Casebash
2
@hackbod:和Casebash一样,我在按照你的指示操作时遇到了问题。给定一个活动,我转储getIntent().toUri(Intent.URI_INTENT_SCHEME).toString(),将其粘贴到网页(http://commonsware.com/sample)中,在模拟器上尝试在浏览器中打开它,但是我得到的选择是在浏览器、联系人或电话中打开页面,而不是我的活动。考虑到来自`toUri()`的`intent:` URI具有component子句,这似乎很奇怪,因此我不确定那些其他应用程序如何获取它。我在意图过滤器上有BROWSABLE类别。如果您有任何想法,请回复我。谢谢! - CommonsWare
4
如果你希望你的URI可靠地工作,请不要尝试这种方法;使用意图URI需要应用程序接受URI的配合。zxing(条形码扫描器)不接受它们(显然是出于故意设计决策),因此如果您想能够通过扫描条形码与您的应用程序交互(或从任何其他您无法完全控制的方法接受URI输入),则需要重载http://(这需要用户在浏览器和您的应用程序之间进行选择)或者使用自定义方案,我认为它会透明地传递到系统中,并且不会被卡住在任何地方。 - womble
4
@hackbod,你能指引我查找W3C的文档来证明不应实现新的URI协议吗?我只找到RFC2718似乎支持这一观点。 - guido
4
@hackbod - 看起来这种方法在iOS上行不通。似乎注册一个独特的 scheme 是最跨平台兼容的实现方式,尽管我同意您的观点,它会污染命名空间...https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW1 - runamok
显示剩余10条评论

47

这是我的直截了当的贡献。

在您想要在清单中加载的活动中创建意图过滤器,如下所示:

<intent-filter>
    <action android:name="com.bubblebeats.MY_CUSTOM_ACTION" />
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>

您的网页URL应该是这样的:

intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;end

从浏览器启动您的apk的最基本的HTML代码如下所示:

<body>
    <a href="intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;end">click to load apk</a>
</body>

添加变量到您的意图

您可以在Android代码中像这样生成URI:

Intent i = new Intent();

i.setAction("com.bubblebeats.MY_CUSTOM_ACTION");
i.putExtra("some_variable", "123456");

Log.d("ezpz", i.toUri(Intent.URI_INTENT_SCHEME));
这将会产生这个结果:
04-13 09:47:30.742: DEBUG/ezpz(9098): intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;S.some_variable=123456;end

你只需要这部分内容:

intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;S.some_variable=123456;end

仔细观察这里发生了什么,你可以看到如何跳过代码步骤并手动创建这些URI。

特别是这部分:

S.some_variable=123456

1
看起来包被附加在 package=com.bubblebeats; 这样的形式中(此外,虽然在这个例子中不明显,但是包已经进行了URI编码)。 - nmr
3
@Jason,你能让这个工作吗?通过 "adb shell am start 'intent:#Intent..." 启动意图对我有效。但是,从浏览器中点击链接意图无法启动应用程序。 - hopia
“S.” 语法在哪里有文档记录?仅依赖于 toUri() 的输出似乎不是一个好主意。 - cYrus
这是一个很好的答案。只是想知道是否在短信中也可以使用相同的方法?我的意思是,在短信中我们无法创建超链接,以便在单击时发送以下调用:intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;end。即使我直接将其放入短信中,我认为它也不会可点击,或者它会吗? - Shobhit Puri
如何使一个webview打开这样的链接?它只在Chrome中有效。 - Roel
显示剩余5条评论

10

因为hackbod没有给我们提供代码示例,所以我想在我成功实现后分享我的代码。

首先,您需要在清单文件中定义一个自定义操作:

<activity
    android:name=".activity.MainActivity"
    android:label="@string/app_name_full">
    <intent-filter>
        <action android:name="com.yourpackage.action.OPEN_VIEW"></action>
        <category android:name="android.intent.category.DEFAULT"></category>
        <category android:name="android.intent.category.BROWSABLE"></category>
    </intent-filter>
</activity>

接下来,对于你网站上的内容,你需要从意图中生成URI。 将以下代码放在你的Activity中(一旦链接被生成,该代码可以被移除):

Intent i = new Intent();
        i.setAction("com.yourpackage.action.OPEN_VIEW");
        i.setPackage("com.yourpackage");
        i.putExtra("myextra","anystring");
        Log.d(getClass().getSimpleName(), i.toUri(Intent.URI_INTENT_SCHEME));

为了接收Extras,在您的活动中添加以下代码,以便能够接收自定义操作(如清单文件中所定义):
final Intent intent = getIntent();
final String action = intent.getAction();

        if ("com.yourpackage.action.OPEN_VIEW".equals(action)) {
           Log.i(getClass().getSimpleName(), "EXTRA: "+intent.getExtras().getString("myextra"));
        }

在您的网站上(这是之前生成的链接):

<a href="intent:#Intent;action=com.yourpackage.action.OPEN_VIEW;package=com.yourpackage;S.myextra=anystring;end">Open App with extra</a>

希望这能帮助一些人更好地理解。如果我有误,请纠正我。


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