GithubHelp home page GithubHelp logo

tencent / shadow Goto Github PK

View Code? Open in Web Editor NEW
7.3K 160.0 1.3K 3.54 MB

零反射全动态Android插件框架

License: BSD 3-Clause "New" or "Revised" License

Java 73.15% Kotlin 26.57% HTML 0.02% AIDL 0.05% Shell 0.21%
android

shadow's Introduction

Shadow

Android CI PRs Welcome

介绍

Shadow是一个腾讯自主研发的Android插件框架,经过线上亿级用户量检验。 Shadow不仅开源分享了插件技术的关键代码,还完整的分享了上线部署所需要的所有设计。

与市面上其他插件框架相比,Shadow主要具有以下特点:

  • 复用独立安装App的源码:插件App的源码原本就是可以正常安装运行的。
  • 零反射无Hack实现插件技术:从理论上就已经确定无需对任何系统做兼容开发,更无任何隐藏API调用,和Google限制非公开SDK接口访问的策略完全不冲突。
  • 全动态插件框架:一次性实现完美的插件框架很难,但Shadow将这些实现全部动态化起来,使插件框架的代码成为了插件的一部分。插件的迭代不再受宿主打包了旧版本插件框架所限制。
  • 宿主增量极小:得益于全动态实现,真正合入宿主程序的代码量极小(15KB,160方法数左右)。
  • Kotlin实现:core.loader,core.transform核心代码完全用Kotlin实现,代码简洁易维护。

支持特性

  • 四大组件
  • Fragment(代码添加和Xml添加)
  • DataBinding(无需特别支持,但已验证可正常工作)
  • 跨进程使用插件Service
  • 自定义Theme
  • 插件访问宿主类
  • So加载
  • 分段加载插件(多Apk分别加载或多Apk以此依赖加载)
  • 一个Activity中加载多个Apk中的View
  • 等等……

编译与开发环境

环境准备

建议直接用最新的稳定版本Android Studio打开工程。目前项目已适配Android Studio Arctic Fox | 2020.3.1, 低版本的Android Studio可能因为Gradle版本过高而无法正常打开项目。

然后在IDE中选择sample-appsample-host模块直接运行,分别体验同一份代码在正常安装情况下和插件情况下的运行情况。

选择sample-host直接运行

Shadow的所有代码都位于projects目录下的3个目录,分别是:

  • sdk包含SDK的所有代码
  • test包含SDK的自动化测试代码
  • sample包含演示代码

其中sample应该是大家体验Shadow的最佳环境。 详见sample目录中的README介绍。

兼容性

Shadow项目有较为完善的自动化测试,因此最新代码对外部环境的版本兼容性可以参考自动化测试的配置。

自己写的测试代码出错?

以我们多年的插件环境下业务开发经验,插件框架是不可能一步到位实现完美的。 因此,我们相信大部分业务在接入时都是需要一定的二次开发工作。 Shadow现有的代码满足的是我们自己的业务现在的需求。得益于全动态的设计, 插件框架和插件本身都是动态发布的,插件包里既有插件代码也有插件框架代码, 所以可以根据新版本插件的需要同时开发插件框架。

例如,ShadowActivity没有实现全所有Activity方法,你写的测试代码可能用到了, 就会出现Method Not Found错误,只需要在ShadowActivity中实现对应方法就可以了。 大部分方法的实现都只是需要简单的转调就能工作正常。

如果遇到不会实现的功能,可以提Issue。最好附上测试代码。

后续开发

  • 原理与设计说明文档
  • 多插件支持的演示工程
  • 自动化测试用例补充
  • 开源包含下载能力的manager实现

贡献代码

详见CONTRIBUTING.md

许可协议

Tencent Shadow采用BSD 3-Clause License,详见LICENSE

个人信息保护规则声明

详见PRIVACY.md

shadow's People

Contributors

alexliusheng avatar antonioshare avatar biaowu avatar bilue404 avatar boyan01 avatar coolbluesky avatar cooper-zhou avatar cylee0909 avatar donglua avatar enzowyf avatar guok2046 avatar hackergeek avatar hotstu avatar igottime avatar kakawar avatar linxueyuanstdio avatar lks6123 avatar o0starshine0o avatar phantomqi avatar richardwrq avatar sheepyang1993 avatar shifujun avatar spaceq-z avatar spenceacc avatar testplanb avatar trevorwang avatar visualrainy avatar weimuhua avatar xuedizi avatar yunanchen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

shadow's Issues

插件打包任务需要独立出来以适应多插件打包场景

目前打包插件任务是实现在某一个“主插件”apply plugin: 'com.tencent.shadow.plugin'中的。对于有多个插件的项目,不是很友好。

目前实现的代码在com.tencent.shadow.core.gradle.extensions.PackagePluginExtension

  1. 应该将其改为一个单独的Gradle Plugin。允许我们新建一个build.gradle,应用这个单独的插件,然后做打包插件的配置。
  2. 允许配置多个插件包共享同一个UUID。

多插件时的UUID问题

当存在多个插件的时候,目前的打包脚本会为每个插件都生成新的uuid,加载插件的时候,就会发生错误,需要固定uuid

./gradlew build failed

> Task :sample-plugin-app:transformClassesWithShadowTransformForDebug FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':sample-plugin-app:transformClassesWithShadowTransformForDebug'.
> javassist.NotFoundException: /Users/twiceyuan/Library/Android/platforms/android-28/android.jar

java.lang.RuntimeException: java.lang.IllegalArgumentException: 无法绑定PPS:com.tencent.shadow.sample.host.PluginProcessPPS

2019-06-26 16:43:35.011 30138-30179/com.baiwan.pk:plugin E/AndroidRuntime: FATAL EXCEPTION: pool-3-thread-1
Process: com.baiwan.pk:plugin, PID: 30138
java.lang.RuntimeException: java.lang.IllegalArgumentException: 无法绑定PPS:com.tencent.shadow.sample.host.PluginProcessPPS
at com.tencent.shadow.a.a.b$1.run(Unknown Source:57)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.IllegalArgumentException: 无法绑定PPS:com.tencent.shadow.sample.host.PluginProcessPPS
at com.tencent.shadow.dynamic.a.b.a(Unknown Source:119)
at com.tencent.shadow.a.a.a.f(Unknown Source:8)
at com.tencent.shadow.a.a.a.e(Unknown Source:0)
at com.tencent.shadow.a.a.a.a(Unknown Source:2)

Dalvik虚拟机,MultiDex异常

崩溃异常信息如下:
java.lang.NullPointerException
at java.io.File.fixSlashes(File.java:185)
at java.io.File.(File.java:134)
at android.support.multidex.MultiDex.install(MultiDex.java:113)
at com.yihuo.goldtiger.GoldTigerApplication.attachBaseContext(GoldTigerApplication.java:78)
at com.tencent.shadow.core.loader.ShadowPluginLoader$callApplicationOnCreate$1.invoke(Unknown Source)
at com.tencent.shadow.core.loader.ShadowPluginLoader$callApplicationOnCreate$2.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)

插件代码如下:
public class GoldTigerApplication extends Application {
@OverRide
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
宿主打开插件在Android4.4的环境下,采用Dalvik运行模式。会出现上述异常。高版本采用ART虚拟机未见该异常。

插件和宿主包名不一致

Caused by: java.util.concurrent.ExecutionException: com.tencent.shadow.core.loader.exceptions.ParsePluginApkException: 插件和宿主包名不一致。宿主:com.baiwan.pk 插件:com.tencent.shadow.sample.host

这个有方法可以使包名不一致吗?
我们项目叫cp方去改包名会比较麻烦

用Shadow编译的apk可以独立运行吗?

我们项目的情况是我们的app是一个宿主app,打算接入其他第三方公司的app,第三方公司的app也是能够独立安装运行的。如果第三方公司用Shadow编译他们的apk,是不是就不能独立安装运行了?

Only fullscreen opaque activities can request orientation

Android8.0 API26
点击主页中启动插件,抛异常:

2019-06-20 09:20:23.618 16264-16264/com.tencent.shadow.sample.host E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tencent.shadow.sample.host, PID: 16264
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tencent.shadow.sample.host/com.tencent.shadow.sample.host.PluginLoadActivity}: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2931)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1620)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6701)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:249)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
at android.app.Activity.onCreate(Activity.java:1005)
at com.tencent.shadow.sample.host.PluginLoadActivity.onCreate(PluginLoadActivity.java:40)
at android.app.Activity.performCreate(Activity.java:7050)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2809)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2931) 
at android.app.ActivityThread.-wrap11(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1620) 
at android.os.Handler.dispatchMessage(Handler.java:105) 
at android.os.Looper.loop(Looper.java:176) 
at android.app.ActivityThread.main(ActivityThread.java:6701) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:249) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783) 

Cannot access first() element from an empty Iterable

Cannot access first() element from an empty Iterable

build 的时候发生问题 模块:sample-plugin

afterEvaluate {
android {
buildTypes.findAll().each { buildType ->
def buildTypeName = buildType.getName()
def task = project.getTasksByName("check${buildTypeName.capitalize()}Classpath", false).first() as Task
task.dependsOn gradle.includedBuild('core').task(':common:jarDebugPackage')
task.dependsOn gradle.includedBuild('dynamic').task(':dynamic-host:jarDebugPackage')
}
}
}

支持AppCompatActivity吗?

我看转换里有
"android.app.Activity" to "com.tencent.shadow.core.runtime.ShadowActivity"
我直接替换为
"android.support.v7.app.AppCompatActivity" to "com.tencent.shadow.core.runtime.ShadowActivity"

jitpack编译错误

从github fork项目,创建版本,然后jitpack构建编译失败,不能引用,jitpack错误如下:
FAILURE: Build completed with 2 failures.

1: Task failed with an exception.

  • What went wrong:
    Execution failed for task ':sample-runtime:processDebugManifest'.

com.android.manifmerger.ManifestMerger2$MergeFailureException: java.io.FileNotFoundException: /home/jitpack/build/projects/sdk/coding/lint/build/intermediates/merged_manifests/debug/processDebugManifest/merged/AndroidManifest.xml (No such file or directory)

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    ==============================================================================

2: Task failed with an exception.

  • What went wrong:
    Execution failed for task ':core:common:generateReleaseRFile'.

java.nio.file.NoSuchFileException: /home/jitpack/build/projects/sdk/coding/lint/build/intermediates/res/symbol-table-with-package/release/package-aware-r.txt

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    ==============================================================================

  • Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.0/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 22s
553 actionable tasks: 534 executed, 19 up-to-date
Build tool exit code: 0
Looking for artifacts...
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8 -Dhttps.protocols=TLSv1.2
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8 -Dhttps.protocols=TLSv1.2
Looking for pom.xml in build directory and ~/.m2
2019-07-22T07:53:36.658571083Z
Exit code: 0

ERROR: No build artifacts found

Multidex的测试用例不可靠

Multidex的测试用例试图拆分成两个dex,并把必要的类保留在第一个dex里。但是实现的不可靠,只是偶尔会正确分dex。

关于Fragment实现的疑惑

目前Fragment的实现方式导致无法直接调试,我想请问一下能否类似Activity一样通过转调方式实现,保留原有的fragment class类呢?

多插件处于不同进程,进行通信的问题总结

插件配置如下:
插件1位于plugin进程,内包含Activity和Service
插件2位于plugin_2进程,内包含Activity,并通过aidl与插件1通信

宿主,可唤起插件1和插件2中的activitym,并通过aidl与插件1通信

现象1:
直接进入插件2的Activity,通过aidl与插件1通信,正常通信,插件1的Service运行在plugin;
退出该activity,回到宿主,通过aidl与插件1通信,正常,插件1的Service运行在plugin;
再从宿主进入插件2的Activity,进入loading页后,有概率闪退回宿主,多试几次后可以成功进入

现象2:
直接进入插件2的Activity,通过aidl与插件1通信,正常通信,插件1的Service运行在plugin;
退出该activity,回到宿主,通过aidl与插件1通信,正常通信,插件1的Service运行在plugin;
反复以上操作,有概率出现在宿主通过aidl与插件1通信时,插件1的Service运行错误运行在plugin_2;

现象3:
直接进入插件1的activity,在loading页立即退出返回宿主界面,然后再进插件1的activity,有概率出现报错“PPS出现多实例”

现象4:
反复多次来回进入和退出两个插件的activity,有概率出现插件2中的activity无法启动,现象同现象1

1和4比较容易复现

Build failed with connection timeout

Now could not resolve com.tencent.shadow.core:common:2.0.12-782812a5-SNAPSHOT from maven, and it warns that 'Remote host closed connection during handshake'.

报错:android.app.ServiceConnectionLeaked

@Override
    public void unbindService(ServiceConnection conn) {
        if (!mPluginComponentLauncher.unbindService(this, conn).first)
            super.unbindService(conn);
    }
@Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        if (service.getComponent() == null) {
            return super.bindService(service, conn, flags);
        }
        Pair<Boolean, Boolean> ret = mPluginComponentLauncher.bindService(this, service, conn, flags);
        if (!ret.first)
            return super.bindService(service, conn, flags);
        return ret.second;
    }

上面两个方法位于ShadowContext类中,在bindService方法中,如果service.getComponent() == null,那么会调用ContextWrapper的bindService方法;而在ShadowContext类的unbindService方法中,if判断条件中mPluginComponentLauncher.unbindService(this, conn)是写死了返回一个Pair(true, Unit)的,也就是说super.unbindService(conn);是一个不可达语句,那么在某些情况下,就会造成调用了ContextWrapper.bindService而没法调用ContextWrapper.unbindService的情况,也就会报错ServiceConnectionLeaked。

发现这个情况是我在Plugin中写了一个Activity,并在这个Activity中绑定了一个位于Host中的Service,并且我在onDestroy方法中写了unbindService方法,在退出这个Activity的时候,报了ServiceConnectionLeaked这个错误。

DexArchiveMergerException

> Task :sample-plugin-app:transformDexArchiveWithDexMergerForDebug FAILED
java.lang.RuntimeException: java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\0, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\3.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\4.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\5.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\6.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\7.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\8.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\9.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\10.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\11.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\12.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\13.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\14.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\15.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\16.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\17.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\18.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\19.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\20.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\21.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\22.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\23.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\24.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\25.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\26.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\27.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\28.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\29.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\30.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\31.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\32.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\33.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\34.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\36.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\37.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\39.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\40.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\42.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\43.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\45.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\46.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\49.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\50.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\52.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\53.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\58.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\59.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\61.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\62.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\65.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\66.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\68.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\69.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\71.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\72.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\74.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\75.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\77.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\78.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\80.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\81.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\84.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\85.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\87.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\88.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\90.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\91.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\93.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\94.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\96.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\97.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\99.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\102.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\103.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\105.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\106.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\108.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\109.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\111.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\112.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\114.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\115.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\117.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\118.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\120.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\121.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\123.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\124.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\126.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\127.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\129.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\130.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\132.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\133.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\135.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\136.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\138.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\139.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\141.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\142.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\144.jar, D:\SheepYang\Android\Project\SheepShadow\projects\sample\sample-plugin\sample-plugin-app\build\intermediates\transforms\dexBuilder\debug\145.jar
Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes.
Program type already present: android.support.v4.content.LocalBroadcastManager$BroadcastRecord
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
	at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
	at java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:720)
	at com.google.common.collect.ImmutableList.forEach(ImmutableList.java:406)
	at com.android.build.gradle.internal.transforms.DexMergerTransform.transform(DexMergerTransform.java:233)
	at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:239)
	at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:235)
	at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:102)
	at com.android.build.gradle.internal.pipeline.TransformTask.transform(TransformTask.java:230)
	at sun.reflect.GeneratedMethodAccessor299.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
	at org.gradle.api.internal.project.taskfactory.IncrementalTaskAction.doExecute(IncrementalTaskAction.java:46)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:41)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:117)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:106)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:85)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:65)
	at org.gradle.api.internal.tasks.execution.ActionEventFiringTaskExecuter.execute(ActionEventFiringTaskExecuter.java:44)
	at org.gradle.api.internal.tasks.execution.TimeoutTaskExecuter.execute(TimeoutTaskExecuter.java:53)
	at org.gradle.api.internal.tasks.execution.SnapshotAfterExecutionTaskExecuter.execute(SnapshotAfterExecutionTaskExecuter.java:38)
	at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
	at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:59)
	at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:49)
	at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:61)
	at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:91)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:44)
	at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:55)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:35)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.run(EventFiringTaskExecuter.java:49)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:44)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:43)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:337)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:325)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:318)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:304)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:134)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:129)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:202)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:193)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:129)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.lang.Thread.run(Thread.java:745)

FileProvider测试报错

TestFileProviderActivity页面点击拍照跳到系统拍照界面然后,拍照成功后返回,TestFileProviderActivity重建了,导致mFile字段为空。会报空指针异常。

从后台下载插件

请问,目前是需要我们自己实现从后台下载插件包的功能是么?后面官方有计划补充上这个功能么?

宿主和插件之间通讯

刚刚提交了一个例子
d25da55

后面再补充其他场景。

Originally posted by @shifujun in #31 (comment)

按照您的方式,我试着增加一个module,然后有个host宿主implementation这个module,插件plugin ComplieOnly这个module,然后插件使用这个module里面的某个类,而且我已经加了whitelist,但是为啥现在还是会报错插件找不到这个宿主的module呢?

百度地图sdk初始化异常

你好,我今天发现百度地图sdk初始化异常,是so加载存在兼容问题吗?百度地图sdk版本是v3.7.3,具体错误堆栈如下:
com.tencent.shadow.sample.host E/zygote64: No implementation found for long com.baidu.platform.comjni.map.commonmemcache.JNICommonMemCache.Create() (tried Java_com_baidu_platform_comjni_map_commonmemcache_JNICommonMemCache_Create and Java_com_baidu_platform_comjni_map_commonmemcache_JNICommonMemCache_Create__)
2019-07-03 16:58:17.755 21619-21619/com.tencent.shadow.sample.host E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tencent.shadow.sample.host, PID: 21619
java.lang.UnsatisfiedLinkError: No implementation found for long com.baidu.platform.comjni.map.commonmemcache.JNICommonMemCache.Create() (tried Java_com_baidu_platform_comjni_map_commonmemcache_JNICommonMemCache_Create and Java_com_baidu_platform_comjni_map_commonmemcache_JNICommonMemCache_Create__)
at com.baidu.platform.comjni.map.commonmemcache.JNICommonMemCache.Create(Native Method)
at com.baidu.platform.comjni.map.commonmemcache.a.a(Unknown Source:2)
at com.baidu.platform.comapi.util.f.b(Unknown Source:6)
at com.baidu.platform.comapi.a.c(Unknown Source:23)
at com.baidu.platform.comapi.c.a(Unknown Source:21)
at com.baidu.mapapi.SDKInitializer.initialize(Unknown Source:0)
at com.baidu.mapapi.SDKInitializer.initialize(Unknown Source:1)

关于宿主和插件进程间通信

我看插件的binder目前没有通过PluginManagerService暴露出来;宿主或者其他插件怎么做到多进程通信。通过每个插件自己的PPS分发么

清理代码造成4.4机器Crash了

4effafd is the first bad commit
commit 4effafd
Author: shifujun [email protected]
Date: Thu Jul 25 14:05:06 2019 +0800

对0757192c及其之前的5个提交对PackageManager改动的补充。
PluginPackageManager没有必要继承系统的PackageManager了。
删除无用的CommonPluginPackageManager。

:040000 040000 697ccf88f78fbac7ad9ea3b747ad6d50d99e495a 62cc08f62f04f0f8e23231a86d77dc054b82e856 M projects

  • 修复问题

  • 确定将4.4机器作为单元测试必选项目

getApplicationInfo有两处实现,且实现不一致。

com.tencent.shadow.core.runtime.ShadowContext#getApplicationInfo
com.tencent.shadow.core.runtime.ShadowPackageManager#getApplicationInfo
两处实现的逻辑不一致,且不应该实现两遍。

其中com.tencent.shadow.core.runtime.ShadowPackageManager#getApplicationInfo返回的ApplicationInfo没有设置sourceDir,导致了问题#38

其中ShadowPackageManager是插件中代码通过PackageManager试图getApplicationInfo,并且传入的packageName等于插件(也等于宿主)的。我们认为这种调用实际上是试图拿到插件自己的ApplicationInfo。因此转调过来了。

插件怎么接入

如题:
直接这样就可以吗? 需要额外配置什么吗?
apply plugin: 'com.tencent.shadow.plugin'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.