为每个 Activity 绑定一个 url 可以方便的让第三方 app 直接打开这些 Activity。也可以方便在 app 内部进行页面跳转,解耦。

背景

举一个常见的案例,假设我们有个产品 A,产品 A 包含 h5 网页端和客户端,当用户在手机打开我们的 h5 网页端的时候,我们会期望如果用户手机安装了我们的客户端,则直接打开 app,否则停留在网页端浏览。

这是一个很常见的需求,但是实现需要 h5 和 Android 的配合,本文会先说下原理,然后单独描述 Android 端需要做的事情,最后会给一个链接说明 h5 的工作。

原理

Android 端先给 Activity 绑定一个 url ,比如说是 myapp://main.

用户访问 http://myapp.com 网页时,h5 尝试访问 myapp://main,如果用户安装了客户端,则会打开相应的 Activity,否则会继续留在 h5 浏览网页。

那么,如何给 Activity 绑定一个 url 是在 Android 端的关键。

Android 实现

创建一个空的 ViewActivity.

  1. public class ViewActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. }
  6. }

AndroidManifest.xml 里面注册 ViewActivity,包含一个 action 为 android.intent.action.VIEWintent-filter

  1. <activity
  2. android:name=".ViewActivity"
  3. android:theme="@android:style/Theme.NoDisplay">
  4. <intent-filter>
  5. <action android:name="android.intent.action.VIEW" />
  6. <category android:name="android.intent.category.DEFAULT" />
  7. <category android:name="android.intent.category.BROWSABLE" />
  8. <data android:scheme="myapp" />
  9. </intent-filter>
  10. </activity>

这样,ViewActivity 就具备了接收 myapp 协议的 android.intent.action.VIEW 事件的能力。比如说,如果某个 app 执行了下面的这段逻辑,我们的 ViewActivity 就可能被打开。

  1. Intent intent = new Intent(Intent.ACTION_VIEW);
  2. intent.setData(Uri.parse("myapp://dosomething"));
  3. startActivity(intent);

刚才之所以说 "可能被打开",是为了严谨。因为完全可能用户手机上,还有另外一个 app 也声明了一样协议的 intent-filter. 这时候系统就会给出一个弹出框,让用户选择一个期望的应用来打开该地址。

既然入口找到了,接下来就简单了,无非就是实现一下 ViewActivity 处理跳转逻辑,比如这样。

  1. public class ViewActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. Uri uri = getIntent().getData();
  6. String url = uri.toString();
  7. if ("myapp://main".equals(url)) {
  8. startActivity(new Intent(ViewActivity.this, MainActivity.class));
  9. } else if ("myapp://user".equals(url)) {
  10. startActivity(new Intent(ViewActivity.this, UserActivity.class));
  11. }
  12. finish();
  13. }
  14. }

但是上面这种,这是一个理想的情况,因为现实情况会复杂的多。比如说会遇到传参问题,打开一个 UserActivity 可能都是需要指定一个 userId 的。不过再怎么复杂,无非就是对一个 url 的解析。

下面会介绍一个我写的开源项目,省掉了解析 url 的麻烦,下面会基于这个库来说明。

这个库叫 ActivityRouter,通过给 Activity 添加注解来绑定 url. 首先我们要把库添加到项目里面来, 需要修改两个 build.gradle 文件。

项目根目录的 build.gradle

  1. buildscript {
  2. dependencies {
  3. classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7'
  4. }
  5. }

app 项目的 build.gradle

  1. apply plugin: 'android-apt'
  2. dependencies {
  3. compile 'com.github.mzule.activityrouter:activityrouter:1.1.1'
  4. apt 'com.github.mzule.activityrouter:compiler:1.1.1'
  5. }

这样,等项目 sync 完 ActivityRouter 就已经被集成在项目里面了。

此外还需要改一个配置,之前在 AndroidManifest.xml 上注册的 ViewActivity 现在要换成 ActivityRouter 里面自带的 Activity,这样 ActivityRouter 才有机会处理相关的 Intent 事件。修改完的 AndroidManifest.xml 如下:

  1. <activity
  2. android:name="com.github.mzule.activityrouter.router.RouterActivity"
  3. android:theme="@android:style/Theme.NoDisplay">
  4. <intent-filter>
  5. <action android:name="android.intent.action.VIEW" />
  6. <category android:name="android.intent.category.DEFAULT" />
  7. <category android:name="android.intent.category.BROWSABLE" />
  8. <data android:scheme="myapp" />
  9. </intent-filter>
  10. </activity>

接下来就是去修改需要绑定 url 的 Activity,添加注解即可,一个典型的实现如下:

  1. @Router("main")
  2. public class MainActivity extends Activity {
  3. }

一个需要参数的 Activity 可以这样声明:

  1. @Router("user/:userId") // :userId 代表参数名为 userId
  2. public class UserActivity extends Activity {
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. String userId = getIntent().getStringExtra("userId"); // 获取参数 userId
  7. }
  8. }

也可以给参数指定类型,比如说常见的 id 为 long 型.

  1. @Router(value = "user/:userId", longExtra = "userId")

这样我们就可以通过 myapp://main 来访问 MainActivity, myapp://user/89757 来访问 UserActivity 并且 userId = 89757 了。

H5 实现

如上文所说网页自动跳转到 app 需要 h5 配合,由于 h5 已经超越了 Android 的范畴,这边就直接贴个链接。

http://t.cn/RqMTBDZ

http://t.cn/RzOQWGU

App 内应用场景

除了第三方 app 跳转场景外,还可以在 app 内部 Activity 跳转时采用 Router 来实现,比如在 Android 端和后端约定好页面对应的 url,后端在发送 push 的时候,就可以发送特定的 url,客户端只需要处理打开 url 即可,可以有效减少 push 通知的适配工作。相关 API 如下:

  1. Routers.open(Context, String)
  2. Routers.open(Context, Uri)

结语

哈哈,感谢你看到这里。

通过 URL 打开 Activity的更多相关文章

  1. Unity3D研究院之打开Activity与调用JAVA代码传递参数

    原地址:http://www.xuanyusong.com/archives/667    Unity for Android 比较特殊,Unity for IOS 打包是将XCODE工程直接交给开发 ...

  2. 打开Activity时,不自动显示(弹出)虚拟键盘

    打开Activity时,不自动显示(弹出)虚拟键盘 在AndroidManifest.xml文件中<activity>标签中添加属性 android:windowSoftInputMode ...

  3. Activity 事件以及如何得到新打开Activity关闭后返回的数据

    1: package com.example.activity_basic; 2:   3: import android.os.Bundle; 4: import android.app.Activ ...

  4. 点击短信中的url打开某个应用

    实现功能: 短信内容中含有url(例如,http://youngo.com/app/),点击后打开apk 遗留问题: 点击url后,会出现选择框,让用户选择是用浏览器打开还是用该apk打开----没有 ...

  5. Android Intent (可通过URL启动 Activity)

    Intent分为两大类: (1)显性的(Explicit) (2)隐性的(Implicit) 对于隐性意图,在某些时候, 应用程序只是想启动具有某种特征的组件, 并不想和某个特定的组件耦合. 使用In ...

  6. crm使用url打开窗口视图

    //URL可寻址元素使您能够包含指向Microsoft Dynamics CRM窗口. 视图. 对话框和其它应用程序中的报告. //这样.您就能够轻松扩展其它应用程序.报表或站点,以便用户无需切换应用 ...

  7. Android学习(八) 打开Activity

    在Android中打开窗口有两种方式,第一种是不需要返回值的,第二种是带返回值的. Main.xml文件,程序从这个窗口开始执行. <LinearLayout xmlns:android=&qu ...

  8. 04_显示意图打开activity

    实际上用显式意图打开一个activity就很简单了.只需要指定你要打开的这个activity的class就可以了. 需要注意一点的是创建了一个ThirdActivity必须要在清单文件里面声明.如果没 ...

  9. 03_隐式意图打开activity

    想让第一个activity把第二个activity打开的话,在清单文件里面声明一下并且 右键Debug As Android Application居然没有报错 mimeType  讲HTML的时候就 ...

随机推荐

  1. Mouse Detected Problem

    通常分三种情形: 鼠标完全不工作鼠标工作一段时间后不工作鼠标的按钮或者滚轮不工作 必要提交信息:1.鼠标的具体厂商和型号2.鼠标连接PC方式:串口.PS/2.USB或无线USB等:3.鼠标的工作机制: ...

  2. java 多线程通知 CountDownLatch 倒数计数器的使用

    package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import org.springframework. ...

  3. django by example 第四章 扩展 User 模型( model)

    描述: RelatedObjectDoesNotExist at /account/edit/ User has no profile.​ 原因: 注意原书,要求新建一个账户才能使用.

  4. docker安装radis

    sudo docker search redis sudo docker pull redis sudo docker run --name redis6379 -p 6379:6379 -v /op ...

  5. Chrome浏览器用AdBlockPlus拦截百度广告

    一:安装AdBlockPlus插件,这个貌似要FQ安装,不知道可不可以本地安装: 二:在右侧的扩展那里找到ABP扩展,然后设置-高级-我的过滤列表栏-开始创建我的过滤列表: 三:在列表栏里添加 bai ...

  6. Vuejs——(3)计算属性,样式和类绑定

    版权声明:出处http://blog.csdn.net/qq20004604   目录(?)[+]   先上总结: (十九)标签和API总结(2) vm指new Vue获取的实例 ①当dom标签里的值 ...

  7. 使用root用户登录到AWS EC2服务器

    首先是在putty中使用ec2-user登录服务器后,创建root账户的密码,使用如下命令: sudo passwd root 然后会提示你输入new password,输入之后回车,会让你retyp ...

  8. docker 安装 RabbitMQ

    1.镜像中国(http://www.docker-cn.com/registry-mirror):直接使用https://hub.docker.com下载镜像比较慢,使用镜像中国加速 使用例子:$ d ...

  9. 【算法python实现】 -- 不同路径II

    原题:https://leetcode-cn.com/problems/unique-paths-ii/ 思路 与上题相同,不过是加了路障.地图上每一格都有两个状态,有路障或无路障,分别以1和0表示其 ...

  10. Maven 的安装与配置

    最近公司需要新起一个项目,想使用maven+springmvc+spring+mybatis+mysql实现,以前我们的项目都是传统的老项目,没用过maven,Eclipse版本是GALILEO的,有 ...