Android如何充分利用scheme

现在的互联网App经常遇到以下几种需求:

  1. 推送收到不同的推送,点击推送会往不同页面跳且带有不同参数,当然还有推送是无通知的方式,即:收到推送做特定的事情;
  2. H5项目之间跳转:因为项目里容纳里多个离线H5的资源包,并以加载网页资源的方式加载模块,这类项目之间本来是完全没有关联的,需要建立桥梁帮他们互相唤起,当然也少不了各种参数;
  3. 外部浏览器跳转至App的固定页面:很多时候公司产品会嵌入广告在其他App里做推广,要求点击那些广告要求带指定参数跳转App指定页面;
  4. 扫码方式跳转至App的固定页面:很多地下推广会以二维码方式呈现在海报上,如果用App扫码后跳指定App页面且带参数;
  5. 短信内容有链接,点击链接带参数跳App某个页面;

  就以上这些场景是不可能每个场景都定义解析规则的,毕竟维护工作会太多,所以只要定义一套解析规则即可,scheme的解析是最特殊的,本着求同存异的思想,因此我们所有的工作以scheme开展开来。这里我给它起了一个名字:AppLink,scheme主要组成为:[scheme]://[host][:port]/[path]?[query],这非常类似http url的定义,我们举个例子:cbdbusbutler://Bus/OrderDetail?orderId=43423,显而易见这是带着订单号打开汽车票订单详情页的AppLink定义。
  关于用scheme用来做跳转的文章其实网上已经有很多,原理大家都很懂,但是我们需要的是真实运用,所以有必要对它进行设计,让业务接入更加容易,因此我写了一个Library,名叫AppLink,我的设计思想是将每种跳转都以一个类来描述,简单说每种跳转都单独定义一个appLink类,并且按模块划分,并且appLink的path就是对应appLink类的package,即: appLink所在packageName + moduleName + className = appLink的classpath。总之,是通过路径反射找到对应的appLink并解析的,其实思路很easy,如何组织代码才是关键。

下面来看看我们的Library如何接入的:

1. 定义schema:

<activity android:name="com.feizhang.applink.AppLinkActivity">
    <intent-filter>
        <data android:scheme="my-scheme" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
    </intent-filter>
</activity>

schema本是用于在AndroidManifest.xml里定义的,但是苦于暂时没法从代码层面获取AndroidManifest.xml里配置的scheme,因此需要代码中也要初始化。

public class MyApplication extends Application {
    private static final String APP_LINK_PACKAGE = "com.feizhang.applink.sample.applink";
    private static final String SCHEME = "my-scheme";

    /**
     * account id is usually dynamic, it maybe a phone number or a uuid generated by server according to your projects。
     */
    public static String accountId = "account_123";

    @Override
    public void onCreate() {
        super.onCreate();
        AppLinkUtils.setup(APP_LINK_PACKAGE, R.drawable.nofication_small_ic, SCHEME);
        
        // 这是对于想通过推送透传来自己控制显示通知的情况而言的,对于直接采用推送sdk来显示推送通知的朋友们可以不用注册它
        // 关于PushNotificationReceiver的实现,其实利用了order broadcast的Priority特性,这里注册的Priority比较低,
        // 另外一个`PushContentReceiver(下面会讲)`的Priority比较高,意味着`PushContentReceiver`没有收到message就会被
        // `PushNotificationReceiver`收到了,然后它负责弹Notification;
        PushNotificationReceiver.register(this, new PushNotificationReceiver() {

            @Override
            public String getAccount(@NonNull Context context) {
                return accountId;
            }

            @Override
            public int getSmallIcon(@NonNull Context context) {
                return R.drawable.nofication_small_ic;
            }
        });
    }
}

因为暂时无法从代码层面获取AndroidManifest.xml里的scheme定义,所以在代码层面也要定义下scheme(切记要一样),

2. 如何非常方便的定义解析规则:

创建package,为每个AppLink创建单独的类,并通过反射获取此类解析并触发跳转。


appLink.png

由上可见,每个package对应每个module,每个package下放有很多class,这些class是按功能命名的,比如:AppHome(打开app)、OrderDetail(打开订单详情页)、NewMsgAlert(通知有新消息)

下面我们以打开订单详情页的AppLink为例:

public class OrderDetail extends AppLink {

    /**
     * 构建收到appLink打开页面的Intent
     */
    @Override
    public Intent onStartActivity(@NonNull Context context) {
        String orderId = params.get("orderId");
        Intent intent = new Intent(context, OrderDetailActivity.class);
        intent.putExtra("orderId", orderId);
        return intent;

        // 如果参数复杂,也可以取json转对象再取值
        XXXObject object = new Gson().fromJson("json", XXXObject.class);
        Intent intent = new Intent(context, OrderDetailActivity.class);
        intent.putExtra("orderId", object.orderId);
        return intent;
    }

    /**
     * 和{@link #onStartActivity(Context)}一并会执行,当收到appLink时候可以做一些额外的工作
     */
    @Override
    public void onExecute(@NonNull Context context) {
        super.onExecute(context);
        Toast.makeText(context, "您的订单有更新", Toast.LENGTH_SHORT).show();
    }

    /**
     * 是否特定账户的信息,对于特定账户的订单推送是需要账户隔离的
     */
    @Override
    public boolean isPrivate() {
        return true;
    }

    /**
     * 是否需要用DB存储,以DB存储是为了下次启动查询到未读状态
     */
    @Override
    public boolean shouldSave() {
        return false;
    }
}

3. AppLink的目标页面(Activity或Fragment)已经打开如何接收appLink?

这个功能场景我们非常熟悉,类似滴滴打车等待附近车辆接单等待推送,或者打开微信好友的聊天页面收到对方发来消息。

public class OrderDetailActivity extends AppCompatActivity {

    private PushContentReceiver mReceiver = new PushContentReceiver() {
        
        /**
         * 告诉receiver当前可以接收处理哪些appLink,
         * 在微信聊天场景就好比可以接收文字消息、表情消息、定位消息等
         */
        @Override
        public List<String> getAppLinks() {
            return Collections.singletonList("my-scheme://product/OrderDetail");
        }

        @Override
        public String getAccount(@NonNull Context context) {
            // 账户ID按具体项目自己方式获取
            return MyApplication.accountId;
        }

        /**
         * 一般这里我们会再次调用订单接口并刷新当前页面
         * @return true: 终止消息传递,即其他receiver收不到此message
         */
        @SuppressLint("SetTextI18n")
        @Override
        public boolean onReceive(@NonNull Context context, @NonNull AppLink appLink) {
            Toast.makeText(context, "订单已刷新", Toast.LENGTH_SHORT).show();
            return true;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_order_detail);
        
        // 注册页页面级appLink广播接收器(内部onDestroy()会自动解除注册)
        PushContentReceiver.register(this, mReceiver, true);
    }
}

3. 让h5模块之间可以相互跳转:

public class DefaultWebClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView paramWebView, @NonNull final String url) {
        if (url.startsWith(MyApplication.SCHEME)) {
            AppLinkUtils.redirect(paramWebView.getContext, url);
            return true;
        }

        // other case
        return true;
    }
}

拦截跳转url,如果发现是自定义appLink则以AppLinkUtils发起跳转。

4. 推送服务使用appLink解析:

@Override
public void onNotifactionClickedResult(Context context, XGPushClickedResult xgPushClickedResult) {
    String appLink = xgPushClickedResult.getCustomContent();
    AppLinkUtils.redirect(context, pushMsg.appLink);
}

以上以信鸽推送作为案例,其实对其他推送sdk都一样类似,仅仅取出appLink并redirect()而已。

  至此,已经介绍完AppLink的使用方式,关于实现代码可以参考这里, 下一篇文章我在介绍下项目中各种红点提醒是如何实现的,现在想说的是它依赖appLink。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,596评论 4 59
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,034评论 1 32
  • 淘宝直播相比其他的直播,因为它自带的商品属性更容易转化粉丝,产生更大的商业价值,电竞直播和娱乐属性更强的秀场直播呢...
    草原火星阅读 367评论 0 0
  • 最近思绪很乱,搞不清楚自己想要什么。人家问我什么都回答不上来,自己脑子又纠结的要命,也不知道自己想要什么。结果问谁...
    熏莉阅读 274评论 0 0
  • 并不是多喜欢夏天,只是冷得刺骨才怀念烈日的温度。我,似乎常常会犯这样的毛病,把眼下的不适夸大,而对于过去经历的以及...
    华东_绍兴_658762阅读 390评论 2 7