前语

最近在搞URL Scheme数据复原相关代码的重构工作,借此整理一下全体的流程。并且在重构过程中呢,还遇到了一个天坑,拿出来与咱们共享一下。假如咱们有更好的方案,欢迎谈论或私信我让我学习一下~

前置知识点

首先咱们对齐一下所需求的前置知识点,防止后边造成了解上的冲突。

URL Scheme

URL Scheme指的是恪守以下格式的URL:

{scheme://action?param1=value1&param2=value2...}

APP识别到URL Scheme数据后,会依据action去履行相应的逻辑。

scheme通常由事务定义好,一般以app层级区分或事务域层级区分,比方”taobao://”、”douyin://”,或者”tbSearch://”、”douyinSearch://”。action指的是行为,比方”user/detail”是打开个人概况页面,”item/detail”是打开产品概况页面等。再由后边的参数决议具体的页面数据。举个比方:

{wodeApp://user/detail?userId=123}

wodeApp识别到这个Url Scheme以wodeApp最初,就知道是它需求的数据,进而解析数据,打开userId为123的用户页面。

URL Scheme来历

Scheme数据的来历能够有许多,最常见的便是剪贴板、H5页面唤端、音讯告诉唤端、短信告诉唤端等。由于后边的内容会涉及到数据来历,场景又比较复杂或许会比较混乱,所以这儿咱们先理清一下。

咱们把一切的唤端(包括H5页面唤端、音讯告诉唤端、短信告诉唤端)统一一下,都称为Intent唤端,由于他们最终给到App的数据都是放在Intent中的,所以后边讲到唤端就不再一一区分了。

那么咱们现在能拿到URL Scheme的场景就分为四种:

  1. 冷发动时从剪贴板获取
  2. 热发动时从剪贴板获取
  3. 冷发动时从唤端Intent中获取
  4. 热发动时从唤端Intent中获取

为什么要分冷热发动呢?由于冷热发动,URL Scheme获取的方式是不相同的,具体后边会说到。

数据复原

数据复原,在产品上是非常重要的。最基本的一种数据复原,便是跳转方针页面。比方用户被音讯推送了某个产品,点击进来后依据解析得到的Scheme数据咱们需求跳转到指定的产品概况页面。别的,咱们或许还需求依据解析的Scheme数据向服务端建议某个恳求,比方从平价产品页面唤端来的用户咱们需求打上用户标签。

一切的依据action指定的事务逻辑,咱们都称之为数据复原。

产品的迭代历程

上面也讲到了,我是由于重构才有机会写这篇文章的。那为什么要重构呢?自然是代码hold不住产品的迭代速度了,这就要从产品的需求讲起。(当然,需求的迭代仅仅重构的原因之一,更主要的原因是之前的代码没封装,写的很乱,责任不清晰,所以才把重构提上日程的..)

有一天,PD找上门来
PD:咱们做个简略的唤端哈,从音讯告诉进来,或者从H5页面唤端进来,咱们能打开相应的页面就行。别的,假如剪贴板里有这样的数据,也要能到达相同的作用。
程序员A:没问题,这项技术现已很成熟了,立刻给你搞出来

最终这个需求的完结,也基本上不存在什么问题。唤端的Intent数据从闪屏页拿到后,传递到主页,主页再依据数据履行相应的Action。别的在主页onResume生命周期中获取剪贴板数据,假如契合Scheme数据协议,也去做相应的Action。

过了一个月,PD又找上门来
PD:咱们唤端需求再做一个通用才干哈。假如唤端数据带了某个api的某个参数,需求在下次恳求这个api的时候把这个参数给带上,然后满足服务端数据的定制化才干。当然了,仍是跟上次相同,假如剪贴板里有这样的数据,也要能到达相同的作用。
程序员A:为啥要这样搞啊?有啥用?
PD:你想啊,比方主页的引荐流理论上对每个人都是不相同的。那如何完结更精准地推送呢?唤端便是一个手法。每个唤端页面唤端的时候,都带上用户相关的数据,然后把这份数据作为接口参数传给服务端,不就能够完结定向推送了嘛。
程序员A:你很有主意,可是我得想一想...

糟了,之前的剪贴板相关的代码要重写了。为什么呢?由于之前是在主页onResume生命周期中获取剪贴板数据,假如剪贴板数据契合Scheme数据协议,就去做相应的Action。但这个新的需求,又有必要确保得在主页恳求发出去之前,就要拿到剪贴板数据并预埋好接口参数,否则就不会起作用了。比方用户冷启App时,假如不在闪屏页预先拿到剪贴板数据并预埋上主页的接口参数的话,到主页做这个逻辑就没法确保是在主页接口恳求前完结参数的预埋了。

那这个逻辑是要放在闪屏页么?也不对,由于在热启App时,是不会通过闪屏页的,但热启时也要有这样的才干,这就要咱们有必要把解析剪贴板的这段逻辑放在BaseActivity中去

下面就来共享一下URL Scheme数据复原改善后的流程。

数据复原流程

剪贴板

冷启:闪屏页onWindowFocusChanged获取剪贴板数据->解析scheme数据(履行预埋接口参数等Action)->跳转主页->主页跳转至方针页面->清空剪贴板

热启:BaseActivity#onWindowFocusChanged获取剪贴板数据->解析(履行预埋接口参数等Action)->跳转方针页面->清空剪贴板

由于某些原因,咱们的项目中闪屏页没有承继BaseActivity,所以这儿分开了两个部分。假如咱们都是统一承继BaseActivity的,那么这部分解析scheme的逻辑是能够合二为一的。

唤端

冷启:闪屏页onCreate获取唤端Intent->解析scheme数据(履行预埋接口参数等Action)->跳转主页->主页跳转至方针页面->清空剪贴板

热启:闪屏页onCreate获取唤端Intent->解析scheme数据(履行预埋接口参数等Action)->跳转方针页面->清空剪贴板

总结

  • 唤端的逻辑悉数在闪屏页的onCreate生命周期做。只有在冷启唤端时需求先跳转至主页,主页再跳转至模板页面。
  • 剪贴板的逻辑,冷启时在闪屏页做剪贴板的获取与解析,热启时在页面基类做剪贴板的获取与解析,解析完数据后统一在页面基类进行方针页面的跳转。之所以放在页面基类而不是主页,是由于热启回APP后或许处于任意一个页面,所以这段逻辑只能放到基类里边去处理。

别的需求留意的一点是,闪屏页的LaunchMode需求设置为singleTask,否则唤端发动时新创建的闪屏页会到浏览器的栈去,不契合事务需求。

踩坑共享

在这个过程中,我也踩了一个大坑..没想到Android对剪贴板的获取有这样的限制。细心的同学或许现已发现了,在重构前咱们是在主页的onResume生命周期去获取剪贴板的,去网上一搜获取剪贴板数据,大部分的答复都是这样:

override fun onResume() {
    window.decorView.post{
        val content = ClipboardService.getInstance().clipboardContent
    }
}

那为什么在方案设计中,却是在onWindowFocusChanged回调中才去获取剪贴板数据呢?由于上面的代码,在部分场景(尤其是闪屏页),是没法确保能拿到剪贴板数据的。

原因

Android获取剪贴板存在限制,有必要在当前Activity取得焦点的情况下才干成功获取到。

闪屏页的生命周期:onCreate->onResume->跳转页面->onPause

闪屏页获取焦点时的回调:onWindowFocusChanged(boolean hasFocus);当回调中hasFocus收到true时,外表当前Activity窗口获取到了焦点。

经实验,当闪屏页跳转页面过快,部分机型(如Redmi k40 pro)onWindowFocusChanged会回调false,收不到true,即一向没有取得过焦点,那么这种情况下就无法获取剪贴板数据(拿到是空字符串)。所以获取剪贴板数据的机遇,不能太早,也不能太晚。不能在onCreate中去获取剪贴板数据,也不能比及产生跳转了再去拿。

其次,由于onWindowFocusChanged回调机遇必在onResume之后,所以即便咱们在onResume中post去拿剪贴板,咱们也没法确保post的Runnable履行的机遇是正正好的。有或许Runnable履行时,闪屏页现已产生跳转了。也有或许Runnable履行时,闪屏页还未获取到焦点。

所以呢,咱们应该把获取剪贴板数据的机遇放到onWindowFocusChanged中去,而闪屏页冷启跳转主页的逻辑,也要放到onWindowFocusChanged之后,确保闪屏页现已获取到焦点了,且成功获取到剪贴板数据了。

总结

通过这篇文章,咱们知道了URL Scheme数据复原的全体流程。假如咱们实际事务中没有类似“依据唤端数据,预埋主页接口参数”这样的需求,其实能够比较简略地就完结了。别的,共享了一下Android上获取剪贴板数据所存在的限制,以及在实际事务中遇到的坑该怎样处理。

文章不足之处,还望咱们多多海涵,多多指点,先行谢过!

参考文章

/post/684490… # Android 外部唤起使用跳转指定页面

/post/702840… # 闲鱼唤端的背面