【发布时间】:2015-07-22 12:41:53
【问题描述】:
背景
我正在开发一个非常受欢迎的应用程序,以至于它的一部分应该成为 SDK(可供开发人员使用),并且该应用程序将拆分为 2 个应用程序(两者都使用SDK)。
据我所知,有多种方法可以创建 SDK 模块(以前在 Eclipse 上称为“项目”):
完全开源(Android 库) - 所有源和资源都是开源的,可以修改。一个例子可能是 Facebook 的 SDK 和大量的 Github 存储库。
单个 Jar 文件,可以关闭源代码。
问题
遗憾的是,我无法将 SDK 开源,并且它应该相对受到保护而不是窥探(混淆等...)。
这里的问题是,SDK 需要使用自己的一些资源(drawables、strings、...),到目前为止(因为我没有很多创建 SDK 的经验)我发现处理 SDK 资源的 2 种方法:
使用反射和/或“context.getResources().getIdentifier”。这很混乱,因为我失去了代码的整个“R”用法。此外,正如我在here 中所写的那样,它存在“styleable”问题。这也使得找到未使用的资源变得困难。
更糟糕的方法:将资源放入 assets 文件夹,将文件以古怪的方式放入 jar 文件中,...
请注意,SDK 的一部分包含自定义视图(例如,从 TextView 扩展的类),因此即使我将 SDK 拆分为 2 个模块 - 资源和 java 文件,两者都可能存在依赖问题(每个都使用另一个)。
问题
有没有办法解决这个问题?
SDK 的代码部分是否可以保持封闭源代码,像往常一样访问“R”文件,让我和任何使用 SDK 的人都能轻松使用?
然后我将如何生成通过 Android Studio 混淆的 jar 文件?是否可以准备好以后通过 gradle 使用它?
我可以将 SDK 的 Android 库制作成一个模糊的 jar 文件,而不用担心“R”文件吗?我问这个是因为这样我可以享受两个世界:对于我们的应用程序,它将保持开源,而对于第三方应用程序,它将是封闭源代码。
编辑:看到这应该很容易,我自己尝试过。我创建了一个全新的 POC 项目,其中包含一个名为“sdkmodule”的 Android 库模块,并将此类添加到其中:
public class SdkClass
{
public String doIt(Context context)
{
return context.getResources().getString(R.string.app_name);
}
}
然后,我让应用程序的模块使用这个,我在里面写了这段代码:
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SdkClass sdkClass=new SdkClass();
Log.d("AppLog","string from SDK:"+sdkClass.doIt(this));
Log.d("AppLog","string with same ID name from app:"+getResources().getString(R.string.app_name));
}
我的预期是第一个日志会打印 SDK 模块中的字符串,第二个日志会显示当前项目的字符串,但我得到了一个异常:
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/example/user/sdkmodule/R$string;
在另一次尝试中,我得到了与应用程序本身(使用 SDK 模块的那个)相同的字符串。而且,在另一次运行中,SDK 生成了我想要的所需字符串。
怎么可能?我该怎么办?
此外,我尝试在 SDK 本身中创建第二个活动,并在那里创建了一个资源,该资源与应用程序本身具有相同的资源名称(用于其布局中的 textView),但是具有不同的值,但是当我到达此活动时,我已经看到了应用程序使用的那个。
这是项目,已压缩(忽略文件夹的名称,我也想尝试风味):
https://drive.google.com/file/d/0B-PZZGk2vPohX25WUDNKTmotUTg/view?usp=sharing
【问题讨论】:
-
Android 库项目的 AAR 格式已可用于 Android Studio 和 Gradle for Android 一年多。 Maven 用户也可以直接使用 AAR。对于 Eclipse/Ant,将 AAR 解压缩到库项目中(使用已编译的 JAR 而不是源代码)并不难,至少对于基本的东西来说(here's a blog post 解释了该过程)。 Play Services SDK 以这种基本方式提供,使用编译后的 Java 字节码而不是源代码。
-
假设我有一个正在运行的应用程序,其中一个模块应该是 SDK(或者如果您愿意,可以使用 2 个模块 - 一个用于资源,一个用于源代码),下一步应该是什么?您提供的网站是 Eclipse 的,它是用于使用 AAR 而不是准备它(尽管知道如何使用它也很重要)。
-
“您给出的网站是为 Eclipse 设计的,它是用于使用 AAR 而不是准备它”——这就是为什么它在讨论使用 AAR 的句子末尾的括号中日食。
标签: android android-studio sdk obfuscation r.java-file