Android正确使用Scheme协议打开App,兼容浏览器scheme的二次跳转

Android正确使用Scheme协议打开App,兼容浏览器scheme的二次跳转


URL Scheme

URL Scheme是一种页面内跳转协议,通过定义自己的URL Scheme协议,可以实现

  1. 从一个APP中打开另外一个APP指定的页面
  2. 从H5页面中跳转到APP指定的页面(实际上就是从一个浏览器中的一个页面跳转到APP指定页面)。

URL Scheme协议格式:
一个完整的完整的URL Scheme协议格式由scheme、host、port、path和query组成,其结构如下所示:

<scheme>://<host>:<port>/<path>?<query>

如下就是一个自定义的URL
openapp://hhong:80/product?productId=10000007
openapp: 即Scheme 该Scheme协议名称(必填)
hhong: 即Host,代表Scheme作用于哪个地址域(必填)
80: 即port,代表端口号
product:即path,代表打开的页面
param: 即query,代表传递的参数

传递参数的方法跟web端一样,通过问号?分隔,参数名和值之间使用等号=连接,多个参数之间使用&拼接。

Scheme使用

既然我们使用scheme来做打开app并跳转的逻辑,那这个scheme应该声明在哪里比较合适呢?如果你的应用在启动页(splash)或者在主界面(main)初始化了一些必要的设置,比如必要的token信息检查交易或者一些其它校验等,没有这些信息会造成崩溃的,这个时候我们就需要在启动页来声明这个scheme了,获取scheme信息保存起来,然后在主界面做处理逻辑,如跳转到其它界面等。当然你也可以声明scheme在其它地方,具体得需要看怎么实现业务比较方便。

scheme跳转
scheme跳转
APP1
APP2启动页保存参数
浏览器
APP2主页
APP2具体页面

如配置SplashActivity完整的打开链接为openapp://hhong:80/product?param=100,需要在AndroidManifest.xml配置(SplashActivity启动模式为默认standard模式)

        <activity android:name=".SplashActivity">

            <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:host="hhong"
                    android:path="/product"
                    android:port="80"
                    android:scheme="openapp" />
            </intent-filter>
        </activity>

定义好scheme相关的参数后,现在我们需要用scheme调起目标app,主要有两种方式

  1. APP中打开另一个APP指定的页面
String url = "openapp://hhong:80/product?productId=10000007";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String intentUri = intent.toUri(Intent.URI_INTENT_SCHEME);
Log.e(TAG, "action是:" + intentUri);
startActivity(intent);

这种方式的跳转比较简单,也是最不容易出错的。

  1. 浏览器中的一个页面跳转到APP指定页面

这种方式的跳转可能同样的代码会导致不同的结果,因为涉及到浏览器,而不同的手机厂商不能保证所有的浏览器内核是一样的,进而可能对scheme的处理也是不一样。
前提:项目用的框架是蚂蚁的MPASS,这个项目可能和正常工程项目不同,因为框架对项目的启动方式做了封装,有兴趣的同学也可以去看下这个框架。
问题:app未启动时,由微信分享出来的链接然后在华为浏览器打开这个链接跳转到指定app时(非桌面图标启动app),第一次是能正常跳转到指定页面,但是app切到后台时,再在华为浏览器打开链接发现竟然不做跳转了,只是将应用切回前台页面,但在小米手机上同样的操作,好像又是正常的,这个把我们搞得一脸懵逼,我们猜测是否和浏览器内核有关,于是我们在Android 自带WebView做scheme的跳转,发现也是正常的。

<div>
    <a href="openapp://hhong:80/product?productId=10000007"></a>
</div>

还有就是浏览器上的scheme跳转,Android这边怎么处理的呢?scheme启动Activity其实用的就是Intent,细心的你肯定发现了第一种方式:APP中打开另一个APP指定的页面的跳转,log打印了一个intentUri:

   String intentUri = intent.toUri(Intent.URI_INTENT_SCHEME);
   Log.e(TAG, "action是:" + intentUri);

打印的结果:

E/MainActivity: action是:intent://hhong:80/product?productId=10000007#Intent;scheme=openapp;end

如果我们在方式1中把intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)加上,打印的结果:

E/MainActivity: action是:intent://hhong:80/product?productId=10000007#Intent;scheme=openapp;launchFlags=0x10000000;end

相比之下,多了个launchFlags字段值,这个值在二次跳转起着重要作用(SplashActivity启动模默认standard),Android FLAG标识和启动模式关系可以看下这两篇文章Android Intent FLAG详解,包括其他的标记的一些解释Android之点击Home键后再次打开导致APP重启问题,我们把项目SplashActivity的启动模式改为singleTask就完美的实现了我们的需求,此时mpass工程点击桌面图标并不会重新走开屏页SplashActivity。
其实华为推送通知跳转到指定页面时,在控制台上配置的就是这个intent,有兴趣的同学可以去看下华为推送官方文档,看下他们如何定义intent的,所以对于Android来说上面的href标签也可以写成这样:

<div>
    <a href="intent://hhong:80/product?productId=10000007#Intent;scheme=openapp;end"></a>
</div>

这两种方式是一样的效果,但是我们从华为浏览器scheme跳转打开app拦截到的intent是携带了FLAG,intent还有些其它的信息,如页面appfilterctrl、当前由哪个应用跳转的application_id。下面是我用正常工程测试浏览器scheme启动跳转app拦截到的intent(测试机是华为手机,可能不同的手机有不同的效果):

华为浏览器
intent://hhong:80/product?productId=10000007#Intent;
scheme=openapp;
category=android.intent.category.BROWSABLE;
launchFlags=0x17000000;
launchHwFlags=0x400;
component=com.example.aapp/.SplashActivity;end

UC浏览器
intent://hhong:80/product?productId=10000007#Intent;
scheme=openapp;
launchFlags=0x13000000;
launchHwFlags=0x400;
component=com.example.aapp/.SplashActivity;end

Android 自带的WebView
intent://hhong:80/product?productId=10000007#Intent;
scheme=openapp;
category=android.intent.category.BROWSABLE;
launchFlags=0x3000000;
launchHwFlags=0x400;
component=com.example.aapp/.SplashActivity;end

桌面图标启动
intent:#Intent;
action=android.intent.action.MAIN;
category=android.intent.category.LAUNCHER;
launchFlags=0x10200000;
component=com.example.aapp/.SplashActivity;sourceBounds=792%201686%201044%202001;end

SplashActivity的启动模式都是默认的standard,最终发现UC浏览器启动app后能正常跳转到页面,但是我再次从浏览器scheme启动app时,不会再跳转指定页面,这一点和桌面启动效果类似,点击桌面图标启动app后,再次点击只会把app切到前台。从上面可以看出主要的区别在于launchFlags,如果将SplashActivity启动模式改为singleTask、singleTop、singleInstance又会是怎样呢?

结论:测试正常工程发现如果SplashActivity的启动模式为standard,scheme二次能否跳转指定页面(能否重新创建SplashActivity)取决于浏览器内核,因为它所携带的launchFlags是不同的;如果SplashActivity的启动模式为singleTask、singleTop、singleInstance,scheme二次都能跳转指定页面,和浏览器内核(携带的launchFlags)无关,但是每次点击桌面图标时都会重新打开app,这个时候我们需要在启动页SplashActivity添加一段代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
//            finish();
//            return;
//        }
        // 避免从桌面启动程序后,会重新实例化入口类的activity
        if (!this.isTaskRoot()) {
            Intent intent = getIntent();
            if (intent != null) {
                String action = intent.getAction();
                if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(action)) {
                    finish();
                    return;
                }
            }
        }
        setContentView(R.layout.activity_splash);
    }

这样就保证了在正常工程下,兼容各种浏览器scheme的二次跳转能正常跳转到指定页面,并且每次点击桌面图标又不会重新打开app了!

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
Android Scheme跳转协议是一种在Android操作系统中用于app之间通信的机制。通过Scheme跳转协议,一个app可以通过调用另一个app的特定功能或界面,实现跳转和传递参数的功能。 Android Scheme跳转协议的实现过程如下: 1. 在待跳转app中,需要先定义一个特定的Scheme,用于唯一标识该app。一般情况下,Schemeapp的包名或自定义的scheme名称组成。 2. 在相应的Activity或Fragment中,通过Intent设置该Activity或Fragment的Scheme,以及需要传递的参数,如数据、标志位等。 3. 在需要跳转到该appapp中,通过调用系统提供的隐式Intent的方式,并设置跳转Scheme以及传递的参数,发起跳转。 4. 如果目标app已安装在设备上,在符合条件的应用列表中,用户可以选择使用app打开链接。 5. 目标app接收到跳转请求后,在其Manifest文件中通过声明Intent过滤器,匹配相应的Scheme和路径,并执行对应的操作或界面跳转需要注意的是,为了保证Scheme跳转的可用性,需要app安装时注册相应的Scheme,以便系统能够正确地将请求导向目标appScheme跳转协议在实际应用中常被用于app之间的跳转和通信,例如在支付宝中使用支付宝Scheme跳转到其他第三方APP完成支付,或者在浏览器使用特定的Scheme跳转到其他APP打开指定的页面等。 总之,Android Scheme跳转协议是一种方便实现app之间通信的机制,通过定义特定的Scheme使用Intent实现跳转和传参,能够提供更丰富的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄小梁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值