John Mayer - Shadow Days
Did you know that you could be wrong
And swear you're right
Some people been known to do it
All their lives
But you find yourself alone
Just like you found yourself before
Like I found myself in pieces
On my hotel floor
Hard times help me see
I'm a good man with a good heart
Had a tough time, got a rough start
But I finally learned to let it go
Now I'm right here, and I'm right now
And I'm open, knowing somehow
That my shadows days are over
My shadow days are over now
Well I ain't no trouble maker
And I never meant her harm
But it doesn't mean I didn't make it
Hard to carry on
Well it sucks to be honest (honest)
And it hurts to be real
But it starts to make some love
That I can finally feel
Hard times let me be
I'm a good man with a good heart
Had a tough time, got a rough start
But I finally learned to let it go
Now I'm right here, and I'm right now
And I'm open, knowing somehow
That my shadow days are over
My shadow days are over now
I'm a good man with a good heart
Had a tough time, got a rough start
But I finally learned to let it go
Now I'm right here, and I'm right now
And I'm open, knowing somehow
That my shadow days are over
My shadow days are over now
My Shadow
Jessie J
You'll never leave me
I wish we could have another minute to finish this fairy tale
Hear your voice and get lost in it cause all I got is broken detail
You were my world and everything in it
So how did you disappear
I won't say this is over, you're still here
You're my shadow, my shadow, I know you're close
You're my shadow, my shadow, everywhere I go
So I, I don't see the need to cry cause you'll never leave my life
You're my shadow, my shadow Oh oh
You'll never leave me
I won't forget, I'll just sit and reminise
Promise I'll keep all your secrets
To have you back with me, my only wish
cause nobody knew me like you did
The words will come to life I've written in my diary
Hide and seek but I know you'll always find me
Count to ten and I know you will appear,
appear-pear no fear, I'm here, here
You're my shadow, my shadow, I know you're close
You're my shadow, my shadow, everywhere I go
So I, I don't see the need to cry cause you'll never leave my life
You're my shadow, my shadow Oh oh
You'll never leave me
Now your gone I swear you won't be alone
My heart beat tapping like it's made of stone
I wont let you down, mute the sound but I can still hear Yeah
& now I'm breaking, see I'm shaking but I know your waiting
Yeah-yeah
You'll never leave me
You're my shadow, my shadow, I know you're close
You're my shadow, my shadow, everywhere I go
So I, I don't see the need to cry cause you'll never leave my life
You're my shadow, my shadow Oh oh
You're my shadow, my shadow, I know you're close
You're my shadow, my shadow, everywhere I go
So I, I don't see the need to cry cause you'll never leave my life
You're my shadow, my shadow Oh oh
You'll never leave me
No, please don't ever leave me No, no, no
my shadow
文本歌词
It’s time to make a start是时候开始了
to get to know your heart是时候去了解你自己的内心了
time to show your face是时候崭露头角了
time to take your place是时候寻找属于你的位置了
In every speck of dust在每一粒细小的灰尘
In every universe在每一个宏大的宇宙
When you feel most alone当你感觉孤单
you will not be alone其实你并未孤单·
Just shine a light on me, shine a light只需给我一点光,一点光
I’ll shine a light on you, shine a light我便愿努力照亮你生命
and you will see my shadow on every wall你将会在每面墙上 看到我的影子
and you will see my footprint on every floor你将会在每一个台阶上 发现我的脚步·
It only takes a spark to tear the world apart毁灭这个世界只需一秒种
these tiny little things that make it all begin是那些微不足道的一切塑造整个宇宙
Just shine a light on me, shine a light
I’ll shine a light on you, shine a light
and you will see my shadow on every wall
and you’ll see my reflection in your free fall
Ooh, Oh Ooh, Ooh, Oh Ooh!
Just shine a light on me, shine a light
I’ll shine a light on you, shine a light
’Cause when your back’s against the wall当你转身背对所有阻碍
that’s when you show no fear at all你就再也无所畏惧
and when you’re running out of time当你比时间跑得更快
that’s when your hit tune start to rhyme你就可以奏出生命的乐章
We won’t be leaving by the same road that we came by 我们不会在在同一条路上撤退
We won’t be leaving by the same road that we came by
We won’t be leaving by the same road that we came by
We won’t be leaving by the same road that we came by
Oh Ooh, Oh Ooh, Oh Ooh, Oh Ooh!
时隔4年。本文再次来聊聊Shadow 这个0 hook的插件库。目前看来,确实是腾讯这个Shadow 插件库做到0 hook api实现插件化。在腾讯内部也是广泛使用,其设计上解藕的非常好,可以独立升级插件的插件依赖库很少造成冲突,可以几个版本的Shadow插件混用不造成异常。
如果还在观望的朋友,相信阅读完本文可以对这个插件库有更多的信心。当然如果是到海外,Google市场,可能需要自己斟酌一二再使用Shadow。毕竟对于Google来说动态更新这个行为也不是它希望的。
不熟悉插件化原理的,可以阅读我之前写插件文章 横向浅析Small,RePlugin两个插件化框架 ,在里面深刻的描述了3年前的插件化的原理。
有什么问题可以来本文 https://wwwjianshucom/p/e1738998abd1 下讨论
Shadow 比起其他插件库多了几个特殊概念。很多人就是上来如何使用,实际上不对Shadow 的整体有一个初步的概念,很难用的好这个库。
对于Shadow来说,可其他的插件库一样分为宿主和插件两个部分。从设计的角度上更加接近RePlugin,需要宿主和插件业务,分别依赖宿主库和插件库。
实际上,对于Shadow来说,插件业务生成的插件包,不仅仅只有一个插件业务的apk。往往是一个由如下4部分组成:
在聊Shadow的使用和实现方案之前,我们稍微的回顾一下hook点最少的RePlugin框架。Hook了一个Context注入了自己的ClassLoader。那么如何在这个基础上进一步前进,实现0 hook。
能不能想办法达到不 hook任何一个位置,从而实现宿主管理插件的功能呢?当然我也没有想出来,只是有不少人已经想出来了,并进行实现。
RePlugin的思路简单说一下,RePlugin把插件框架氛围两个部分:
为什么需要Hook Context呢?为了让插件和宿主可以互相通信。RePlugin会生成一个PluginClassLoader 用于宿主和插件互相查找对方类。而apk的classLoader 最早是存在Context中,因此需要Hook Context。
既然知道了为什么需要Hook Context了?我们可否想办法处理一下,避免Hook Context。其实方案已经摆在眼前了。
就以坑位Activity为例子。插件库的Gradle 插件转化的PluginActivity 需要正常工作就需要Hook Context。那么我们为何不做如下行为,干脆把Context也交给我们来代理好了,PluginActivity不继承任何类。PluginActivity 将会实现所有Activity 对外的接口,而他所有行为直接以来宿主的坑位Activity了,不久好了吗?
回头来想想我四年前说过的,插件化需要跨越的三大问题,这么做是否解决?
这么想,0 hook 通过代理设计模式实现插件化似乎可行。而Shadow 也是如此思想。接下来看看他如何使用,如何解耦插件库和宿主库的。
为了避免插件库影响原来的业务逻辑,一般会常见一个壳模块。这个模块作为主模块,被业务工程依赖。
在工程根目录的buildgradle 新增
注意,classpath, comtencentshadowcore:gradle-plugin 插件是将所有的四大组件,替换成Shadow的对应的代理类。而这些代理类会把工作交给runtime中真正的Activity组件实现
有了这个 shadow 任务实现后,就能通过命令 /gradlew packageDebugPlugin 直接生成 runtime的apk + loade的apk + 插件业务的apk 的压缩包。
最后记得依赖业务模块
宿主通过如下方法启动插件的Activity
构建一个 application 级别的工程,依赖
请实现几个坑位Activity:
紧接着,生成一个loader-apk即可。
这几个Activity可以不用注册当前apk的AndroidManifest中,需要注册到宿主apk中的AndroidManifest。对于Shadow来说,只需要能在这个apk中找到这个Class就可以了。
请在宿主的AndroidManifest 注册上面申明的Activity
宿主:
请注意必须都申明好 android:process=":plugin" ,需要和承载插件业务 MainPluginProcessService 在同一个进程,这样才能在插件进程中从ClassLoader找到这几个类。
构建一个 application 级别的工程,依赖
构建一个 CoreLoaderFactoryImpl :
注意 CoreLoaderFactoryImpl 这个类名必须固定,这是Shadow自身的hook点。宿主会通过manager 进行查找。
核心是构建 ComponentManager 这个类中,loader将会实现把 runtime 中写好的代理Activity和插件业务的Activity进行一一映射。
案例如下:
到运行的时候,GameActivity 所有的行为将会依赖PluginNativeProxyActivity 的实现。
其他的Activity 映射到 普通的PluginDefaultProxyActivity 即可
需要专门构建一个Android工程,这个工程可以参照github中的案例。
新增配置:
新增依赖:
继承FastPluginManager
先来看看宿主的原理。宿主想要启动插件中的某个Activity需要经历如下几个步骤:
在这个方法中实际上就是校验了 managerapk 的和之前的md5是否一致,不是则需要更新。
发现了更新则执行如下几个步骤:
ManagerImplLoader 实际上是获得了 managerapk 文件后,
并根据 managerapk 文件生成两个对象:
最后通过 ApkClassLoader 查找这个apk中的 comtencentshadowdynamicimplManagerFactoryImpl 类并实例化后,调用 buildManager 生成 PluginManagerImpl 对象。
接下来的逻辑就是进入到了Managerapk中了,是不是有点Replugin那味道了。
因此在manager工程中需要 写一个类名 ManagerFactoryImpl ,作为Managerapk逻辑的入口。因此此时在宿主中返回的 PluginManagerImpl 实际上就是自己编写的manager工程中返回的 SamplePluginManager 类。
在这个案例中, SamplePluginManager 继承的是 PluginManagerThatUseDynamicLoader 紧接着调用SamplePluginManager 的 onCreate 和 onDestroy。
demo中的enter
一般的在SampleManager 中都会,都会根据 fromId 的业务类型来判断当前执行行为。就以 FROM_ID_START_ACTIVITY 为例子。这里尝试着启动 plugin-debugzip 插件包中的插件。
而这个插件包存在着三个apk, loaderapk , runtimeapk , $插件业务apk 因此可以说managerapk管理了当前插件的加载逻辑。
为了不阻塞进程,一般都会开启一个线程,进行加载插件包apk的数据。当加载成功后,就会启动插件的Activity。
能看到这三个方法之间的关系:
还记得在SampleManager中重载的 getPluginProcessServiceName 方法,其中写死了一个Service的类名:
实际上是通过 bindPluginProcessService 这个方法启动这个Service:
能看到这个过程十分的简单,实际上就是通过宿主的Context的bindService方法,启动一个固定类名的Service。并监听 onServiceConnected 方法,回调抽象方法 onPluginServiceConnected
而 onPluginServiceConnected 有两种实现,BaseDynamicPluginManager 的子类有两个:
这里就挑选 PluginManagerThatUseDynamicLoader 进行解析。
能看到这个过程,把对方服务端回调的Binder对象包裹成 PpsController 对象。
并调用PpsController对象的setUuidManager设置uuid给远端Service进程。接着通过 getPluginLoader 获取远端Service的Binder对象,并包装成 BinderPluginLoader 用于通信。
之后把所有的数据都往PpsController和PluginLoader通信相当于让所有的行为都交给远端Service所在的进程处理。
因为Context是从宿主中传递过来的,因此需要把该 getPluginProcessServiceName 对应的服务端类名注册到宿主中,且Class也需要声明在宿主中。
简单的看看宿主都做了什么吧。
需要现在宿主中声明:
然后MainPluginProcessService继承PluginProcessService。
所有的事务交给 PluginProcessService 处理。能看到在这里,一般都会通过 android:process 标示完全不同的进程。所有的组件也会生存在这个进程,因此在声明坑位的时候,需要和 MainPluginProcessService 标示为同一个进程。
[MeasureTime]
Measure=Time
Format="#Hours#"
改为
[MeasureTime]
Measure=Time
Format="%H"
欢迎分享,转载请注明来源:品搜搜测评网