-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(dynamic): 抽出dynamic-apk模块以便复用于其他动态加载apk的场景
添加`projects/sample/hello`示例演示其用法。 close #598
- Loading branch information
1 parent
a499e0d
commit 159ab13
Showing
48 changed files
with
1,886 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
6 changes: 6 additions & 0 deletions
6
projects/sample/dynamic-apk/sample-hello-api-holder/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
演示如何将自定义接口动态化,使得宿主能够使用apk中的实现 | ||
|
||
sample-hello-api:定义宿主api接口 | ||
sample-hello-api-holder:将 api 动态化,宿主通过这个包提供的方法来获取apk中的实现 | ||
|
||
宿主引入 apk 包,implementation project(':sample-hello-api-holder') |
31 changes: 31 additions & 0 deletions
31
projects/sample/dynamic-apk/sample-hello-api-holder/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
apply plugin: 'com.android.library' | ||
|
||
android { | ||
compileSdkVersion project.COMPILE_SDK_VERSION | ||
|
||
defaultConfig { | ||
minSdkVersion project.MIN_SDK_VERSION | ||
targetSdkVersion project.TARGET_SDK_VERSION | ||
versionCode project.VERSION_CODE | ||
versionName project.VERSION_NAME | ||
|
||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | ||
|
||
} | ||
|
||
buildTypes { | ||
release { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||
} | ||
} | ||
} | ||
|
||
dependencies { | ||
// 使用 api 而不是 compileOnly:发布 aar 时会传递依赖,而不是打包进 aar | ||
api 'com.tencent.shadow.core:utils' | ||
api 'com.tencent.shadow.core:common' | ||
api 'com.tencent.shadow.dynamic:dynamic-apk' | ||
|
||
api project(':sample-hello-api') | ||
} |
21 changes: 21 additions & 0 deletions
21
projects/sample/dynamic-apk/sample-hello-api-holder/proguard-rules.pro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
1 change: 1 addition & 0 deletions
1
projects/sample/dynamic-apk/sample-hello-api-holder/src/main/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<manifest package="com.tencent.shadow.sample.apk.hello" /> |
98 changes: 98 additions & 0 deletions
98
...mple-hello-api-holder/src/main/java/com/tencent/shadow/sample/apk/hello/DynamicHello.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Tencent is pleased to support the open source community by making Tencent Shadow available. | ||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. | ||
* | ||
* Licensed under the BSD 3-Clause License (the "License"); you may not use | ||
* this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* https://opensource.org/licenses/BSD-3-Clause | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.tencent.shadow.sample.apk.hello; | ||
|
||
import android.content.Context; | ||
import android.os.Bundle; | ||
import android.text.TextUtils; | ||
import android.widget.TextView; | ||
|
||
import com.tencent.shadow.core.common.Logger; | ||
import com.tencent.shadow.core.common.LoggerFactory; | ||
import com.tencent.shadow.sample.api.hello.IHelloWorld; | ||
import com.tencent.shadow.sample.api.hello.IHelloWorldImpl; | ||
|
||
import java.io.File; | ||
|
||
import static com.tencent.shadow.core.utils.Md5.md5File; | ||
|
||
|
||
public final class DynamicHello implements IHelloWorld { | ||
|
||
final private HelloWorldUpdater mUpdater; | ||
private IHelloWorldImpl mHelloWorldImpl; | ||
private String mCurrentImplMd5; | ||
private static final Logger mLogger = LoggerFactory.getLogger(DynamicHello.class); | ||
|
||
public DynamicHello(HelloWorldUpdater updater) { | ||
if (updater.getLatest() == null) { | ||
throw new IllegalArgumentException("构造DynamicPluginManager时传入的PluginManagerUpdater" + | ||
"必须已经已有本地文件,即getLatest()!=null"); | ||
} | ||
mUpdater = updater; | ||
} | ||
|
||
@Override | ||
public void sayHelloWorld(Context context, TextView textView) { | ||
if (mLogger.isInfoEnabled()) { | ||
mLogger.info("sayHelloWorld context:" + context); | ||
} | ||
updateImpl(context); | ||
mHelloWorldImpl.sayHelloWorld(context, textView); | ||
mUpdater.update(); | ||
} | ||
|
||
public void release() { | ||
if (mLogger.isInfoEnabled()) { | ||
mLogger.info("release"); | ||
} | ||
if (mHelloWorldImpl != null) { | ||
mHelloWorldImpl.onDestroy(); | ||
mHelloWorldImpl = null; | ||
} | ||
} | ||
|
||
private void updateImpl(Context context) { | ||
File latestImplApk = mUpdater.getLatest(); | ||
String md5 = md5File(latestImplApk); | ||
if (mLogger.isInfoEnabled()) { | ||
mLogger.info("TextUtils.equals(mCurrentImplMd5, md5) : " + (TextUtils.equals(mCurrentImplMd5, md5))); | ||
} | ||
if (!TextUtils.equals(mCurrentImplMd5, md5)) { | ||
HelloImplLoader implLoader = new HelloImplLoader(context, latestImplApk); | ||
IHelloWorldImpl newImpl = implLoader.load(); | ||
Bundle state; | ||
if (mHelloWorldImpl != null) { | ||
state = new Bundle(); | ||
mHelloWorldImpl.onSaveInstanceState(state); | ||
mHelloWorldImpl.onDestroy(); | ||
} else { | ||
state = null; | ||
} | ||
newImpl.onCreate(state); | ||
mHelloWorldImpl = newImpl; | ||
mCurrentImplMd5 = md5; | ||
} | ||
} | ||
|
||
public IHelloWorld getHelloWorkdImpl() { | ||
return mHelloWorldImpl; | ||
} | ||
|
||
} |
81 changes: 81 additions & 0 deletions
81
...e-hello-api-holder/src/main/java/com/tencent/shadow/sample/apk/hello/HelloImplLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Tencent is pleased to support the open source community by making Tencent Shadow available. | ||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. | ||
* | ||
* Licensed under the BSD 3-Clause License (the "License"); you may not use | ||
* this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* https://opensource.org/licenses/BSD-3-Clause | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.tencent.shadow.sample.apk.hello; | ||
|
||
import android.content.Context; | ||
|
||
import com.tencent.shadow.core.common.InstalledApk; | ||
import com.tencent.shadow.dynamic.apk.ApkClassLoader; | ||
import com.tencent.shadow.dynamic.apk.ChangeApkContextWrapper; | ||
import com.tencent.shadow.dynamic.apk.ImplLoader; | ||
import com.tencent.shadow.sample.api.hello.HelloFactory; | ||
import com.tencent.shadow.sample.api.hello.IHelloWorldImpl; | ||
|
||
import java.io.File; | ||
|
||
final class HelloImplLoader extends ImplLoader { | ||
//指定实现类在apk中的路径 | ||
private static final String FACTORY_CLASS_NAME = "com.tencent.shadow.dynamic.impl.HelloFactoryImpl"; | ||
private static final String[] REMOTE_PLUGIN_MANAGER_INTERFACES = new String[] | ||
{ | ||
"com.tencent.shadow.core.common", | ||
//注意将宿主自定义接口加入白名单 | ||
"com.tencent.shadow.sample.api.hello" | ||
}; | ||
final private Context applicationContext; | ||
final private InstalledApk installedApk; | ||
|
||
HelloImplLoader(Context context, File apk) { | ||
applicationContext = context.getApplicationContext(); | ||
File root = new File(applicationContext.getFilesDir(), "HelloImplLoader"); | ||
File odexDir = new File(root, Long.toString(apk.lastModified(), Character.MAX_RADIX)); | ||
odexDir.mkdirs(); | ||
installedApk = new InstalledApk(apk.getAbsolutePath(), odexDir.getAbsolutePath(), null); | ||
} | ||
|
||
IHelloWorldImpl load() { | ||
ApkClassLoader apkClassLoader = new ApkClassLoader( | ||
installedApk, | ||
getClass().getClassLoader(), | ||
loadWhiteList(installedApk), | ||
1 | ||
); | ||
|
||
Context contextForApi = new ChangeApkContextWrapper( | ||
applicationContext, | ||
installedApk.apkFilePath, | ||
apkClassLoader | ||
); | ||
|
||
try { | ||
HelloFactory factory = apkClassLoader.getInterface( | ||
HelloFactory.class, | ||
FACTORY_CLASS_NAME | ||
); | ||
return factory.build(contextForApi); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
@Override | ||
protected String[] getCustomWhiteList() { | ||
return REMOTE_PLUGIN_MANAGER_INTERFACES; | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
...hello-api-holder/src/main/java/com/tencent/shadow/sample/apk/hello/HelloWorldUpdater.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Tencent is pleased to support the open source community by making Tencent Shadow available. | ||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. | ||
* | ||
* Licensed under the BSD 3-Clause License (the "License"); you may not use | ||
* this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* https://opensource.org/licenses/BSD-3-Clause | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.tencent.shadow.sample.apk.hello; | ||
|
||
import java.io.File; | ||
import java.util.concurrent.Future; | ||
|
||
/** | ||
* apk文件升级器 | ||
* <p> | ||
* 注意这个类不负责什么时候该升级 实现IHelloWorld的apk文件, | ||
* 它只提供需要升级时的功能,如下载和向远端查询文件是否还可用。 | ||
*/ | ||
public interface HelloWorldUpdater { | ||
/** | ||
* 更新 | ||
*/ | ||
Future<File> update(); | ||
|
||
/** | ||
* 获取本地最新可用的 | ||
* @return <code>null</code>表示本地没有可用的 | ||
*/ | ||
File getLatest(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
演示如何将自定义接口动态化,使得宿主能够使用apk中的实现 | ||
|
||
sample-hello-api:定义宿主api接口 | ||
sample-hello-api-holder:将 api 动态化,宿主通过这个包提供的方法来获取apk中的实现 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
apply plugin: 'com.android.library' | ||
|
||
android { | ||
compileSdkVersion project.COMPILE_SDK_VERSION | ||
|
||
defaultConfig { | ||
minSdkVersion project.MIN_SDK_VERSION | ||
targetSdkVersion project.TARGET_SDK_VERSION | ||
versionCode project.VERSION_CODE | ||
versionName project.VERSION_NAME | ||
|
||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | ||
|
||
} | ||
|
||
buildTypes { | ||
release { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
projects/sample/dynamic-apk/sample-hello-api/proguard-rules.pro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
1 change: 1 addition & 0 deletions
1
projects/sample/dynamic-apk/sample-hello-api/src/main/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<manifest package="com.tencent.shadow.sample.api.hello" /> |
Oops, something went wrong.