为 Wear OS 和普通应用程序构建的 Android Studio 项目,但共享源文件 [英] Android Studio project that builds for both Wear OS and normal app, but shares source files

查看:33
本文介绍了为 Wear OS 和普通应用程序构建的 Android Studio 项目,但共享源文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常小的 Android 应用,已移植到 Wear OS.它工作正常.但是现在我有两个独立的项目,它们的源文件 99.5% 相同.如何将两个版本放在一个项目中,这样每个公共源文件只需要一个副本?

I have a very small Android app that I have ported to Wear OS. It works OK. But now I have two separate projects, whose source files are 99.5% identical. How can I put both versions in one project, so only one copy of each common source file is needed?

(比如Manifest文件需要裁剪——至少对于uses-feature android.hardware.type.watch,一个源文件需要不同——菜单Android 应用程序必须在 Wear 应用程序上进行不同的处理.一种资源是为小屏幕尺寸量身定制的.其他一切都相同.)

(For instance, the Manifest file needs to be tailored -- at least for the uses-feature android.hardware.type.watch, and one source file needs to be different -- menus in the Android app have to be handled differently on the Wear app. One resource was tailored for the small screen size. Everything else is identical.)

我尝试在一个项目中制作两个模块,一个应用程序"另一个磨损".但由于模块似乎是对应目录的,这并不能直接解决共享源文件的问题.

I tried making two modules in the one project, one "app" the other "wear". But since modules seem to correspond to directories, this doesn't directly address the problem of shared source files.

我玩过构建配置"——但我对那里的路径一无所知.我花了一些时间在处理依赖项"的构建类型"上,但我无法弄清楚如何让一个模块查看另一个模块的目录树,比如 res/目录.

I played with "Build Configurations" -- but I see nothing about paths there. I spent some time with "Build Types", which deal with "dependencies", but I couldn't sort out how to make one module look into the other module's directory tree for, say a res/ directory.

解决这个问题的正确方法是什么?

What is the right way to resolve this?

推荐答案

namespaces

保持不同模块的源和资源的命名空间不同很重要.具体如何完成是任意的.

namespaces

It is important to keep the namespaces of source and resources of different modules distinct. Exactly how this is done is arbitrary.

在一个共享代码和资源的 Android 应用和 Wear OS 应用的简单案例中,我采用了以下结构:

In a simple case of an Android app and a Wear OS app that share code and resources, I adopted the following structure:

org.domain.theproject
    <shared code and resources under this>
    org.domain.theproject.app
        <Android app code and resources>
    org.domain.theproject.wear
        <Wear OS app code and resources>
    

每个模块的命名空间在 Gradle 构建文件中定义.

The namespace of each module is defined in the Gradle build file.

如果一切都设置正确,依赖模块的资源将与库模块的资源合并,以便像

If everything is set up properly, resources for dependent modules are merged with those of the library module, so that a reference such as

android:icon="@mipmap/ic_launcher"

可以引用在库模块中定义的同名资源,或者在

could refer to a resource of that name defined in the library module, or one defined in the

(不知道资源名冲突会怎样.)

(I don't know what happens when there is a resource name conflict.)

我一直在 Android 应用程序和 Wear OS 应用程序的项目中使用这种结构共享一个公共库:

I have been using this structure in projects where an Android app and a Wear OS app share a common library:

TheProject/
    AppModule/
        src/main/
            java/org/domain/theproject/
                app/
                    <Android app source files>
            res/
                layout/
                < etc. >
    SharedModule/
        src/main/
            java/org/domain/theproject/
                <shared library source files>
            res/
                layout/
                <etc. >
    WearModule/
        src/main/
            java/org/domain/theproject/
                wear/
                    <Wear OS app source files>
            res/
                layout/
                < etc. >

清单

  • 每个模块都必须有自己的清单文件,AndroidManifest.xml,位于

    src/main/

    不过,只有应用程序的那些才会复制到最终的 APK 文件中.

    Only those for apps are copied into the final APK file, though.

    • 库模块有一个非常简单的清单:两行就足够了,比如:

    • Library modules have a very simple manifest: two lines suffice, something like:


    这用于指示可以访问该库的编译资源的包.

    This serves to indicate the package under which compiled resources of that library can be accessed.

    • Wear OS 或 Android 应用程序的模块清单将更加复杂——通常的元素结构

    • Manifests for modules for Wear OS or Android apps will be more elaborate -- the usual structure with elements

    清单中以点."为前缀的软件包名称相对于 标签的 package 属性.其他包,尤其是共享库模块中的包,可以通过完整的显式包路径访问.

    Names of packages within the manifest prefixed with a dot '.' are relative to the package attribute of the <manifest> tag. Other packages, especially those within a shared library module, may be accessed by a full explicit package path.

    上面的包结构可以通过如下结构的清单巧妙地实现:

    The above package structure can be neatly realized by a manifest structured like this:

    <manifest 
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="org.domain.theproject.app">
        <!-- ... -->
        <application >
            <activity android:name=".MainActivity">
                <!-- ... -->
    

    活动名称将被理解为 org.domain.theproject.app.MainActivity.

    The activity name will then be understood to be org.domain.theproject.app.MainActivity.

    另外,package 属性为 Java 代码中的 R 资源提供了一个包:在上面的例子中,默认的 R 实际上是org.domain.theproject.R.

    Also, the package attribute provides a package for the R resource in Java code: in the above case, the default R is really org.domain.theproject.R.

    • 清单中引用的资源 ... 位于一种平面命名空间中,由库资源和依赖模块资源的资源名称合并而成.很容易发生冲突.

    build.gradle 文件必须以

    apply plugin: 'com.android.library'
    

    App build.gradle 文件必须以

    apply plugin: 'com.android.application'
    

    除了通常的模块依赖之外,应用模块的 build.gradle 必须列出对它们使用的库模块的依赖.例如,如果一个应用程序模块依赖于库模块共享",那么它的 build.gradle 文件必须在它的依赖项部分中指明该依赖项,例如:

    Besides the usual module dependencies, the build.gradle of app modules must list dependencies on the library modules they use. For instance, if an app module is dependent on library module "shared", then its build.gradle file must indicate that dependency in its dependencies section, like:

    dependencies {
        implementation project(':shared')
        //...
    }
    

    当然,Wear OS 应用程序的 build.gradle 文件也有 Wear OS 的依赖项,Android 应用程序也有 AndroidX 的依赖项.但是如果它们依赖的库具有相同的外部依赖,则可能会发生链接冲突.参见外部库依赖项"下面.

    Of course, build.gradle files for Wear OS apps will also have dependencies for Wear OS, and Android apps will have dependencies for, say, AndroidX. But if a library they depend on has the same external dependencies, linking conflicts may occur. See "external library dependencies" below.

    注意 applicationId 属性,如

    android {
     defaultConfig {
            applicationId "org.domain.theproject"
            }}
    

    不一定反映 Java 类结构(尽管这是一个很好的约定).它是应用程序(或包?)的标识符,操作系统使用它来识别应用程序.

    does not necessarily reflect the Java class structure (although that is a good convention). It is rather the identifier for the app (or package?) that the OS uses to identify the app.

    Android Studio 会不自觉地将信息收集起来,并且经常对信息放在哪里感到困惑.各种令人费解的行为导致了很多时间的浪费.(这只是程序中错误感染的一个一般领域.)

    Android Studio squirrels information away willy-nilly, and regularly gets confused as to what it put where. All sorts of perplexing behavior results and much time is wasted. (This being just one general area of bug infestations in the program.)

    事情变得毫无意义的情况经常发生,并且

    It happens horribly often that things stop making sense, and

    Build -> "Clean Project" 
    

    还不够,而且还不够,再加上

    does not suffice, and nor does that, plus

    File -> "Sync Project with Gradle Files".  
    

    有时必须

    File -> "Invalidate Caches/Restart"
    

    事实是,有时必须关闭 AS,使用控制台进入,然后手动删除隐藏目录等.我不会在这里讨论.

    And the fact is, sometimes one must turn AS off, go in with a console, and manually delete the hidden directories etc. I will not go into that here.

    在做这里描述的事情时,你肯定会遇到这样的问题,尤其是在资源和 Java 代码之间的 R 接口方面.我没有任何明确的方法来确定这些问题何时发生,或采取何种措施.你只需要培养一种感觉.

    In doing the sorts of things described here, you will surely run into such issues, especially where it comes to the R interface between resources and Java code. I don't have any clear way to identify when these problems are happening, or which measure to take. You just have to develop a feeling for it.

    对于那些有 Java 经验的人来说很明显:Java 文件中的包名必须反映目录结构;在 AS 中,这意味着相对于模块的目录

    Obvious to those experienced with Java: the package names in Java files must reflect the directory structure; within AS, that means relative to the module's directory

    src/main/java/
    

    库模块类与依赖模块的类合并在那个级别——类名可以在通常的模块之间导入爪哇方式.所以为了实现上面的结构,一个Java文件

    Library module classes are merged with those of the dependent modules at that level -- class names can be imported across modules in the usual Java way. So to effect the structure above, a Java file

    如果 Gradle 配置和清单配置正确,则可以从依赖模块访问库模块中的类,就像模块的 src/main/java 目录下的目录已合并一样.

    If the Gradle config and manifest are configured properly, classes from the library module can be accessed from dependent modules as though the directories beneath the modules' src/main/java directory had been merged.

    保存自动生成的资源包R的包是由模块清单文件中的 标签的 package 属性定义.但是可以显式引用其他包中定义的资源.

    The package that holds the automatically-generated resource package R is defined by the <manifest> tag's package attribute in the module's manifest file. But it is possible to refer explicitly to resources defined within other packages.

    例如,在依赖的应用程序包的代码中

    For instance, within the code of the dependent app package

    org.domain.theproject.app,
    

    非限定符号R指的是生成的资源包

    the unqualified symbol R refers to the generated resource package

    org.domain.theproject.app.R
    

    库包的资源

    org.domain.theproject
    

    可以通过

    org.domain.theproject.R
    

    共享库中的 R 包

    将传统应用程序代码转换为共享库的一个烦恼:R 中的元素不是静态的——因此它们不能在 switch 语句中使用.将它们转换为 if...else 没什么大不了的,但是如果你有很多...

    the R package in shared libraries

    An annoyance of converting conventional app code to a shared library: the elements in R are not static -- so they can't be used in switch statements. It's not a big deal to convert them to if...else, but if you have a lot of them...

    TODO -- 如何从依赖模块的资源中访问库模块的资源?

    TODO -- how to access resources of a library module from within resources of a dependent module?

    库模块的最低SDK版本是可能的低于依赖的应用程序模块,但不是相反.

    It is possible for the minimum SDK version of the library modules to be lower than that of the dependent app modules, but not the other way around.

    因此,Wear OS 模块的最低 SDK 版本可能是 Wear 应用程序的最低版本 (23),而同一项目中的 Android 应用程序模块的数量可能是 AndroidX (14) 中最低的,前提是共享库模块的最低 SDK 版本设置为 14.

    Thus, the minimum SDK version for a Wear OS module could be the lowest possible for Wear apps (23), while that of the Android app module in the same project could be the lowest possible for AndroidX (14), provided the shared library module has its minimum SDK version set to 14.

    所有模块的目标 SDK 版本应该匹配.(我想 - 还没有检查.)

    The target SDK versions of all modules should match. (I guess -- haven't checked.)

    我通过简单的例子来避免使用 Jetifier,通过手动解决依赖模块和库模块之间的依赖冲突.这样,APK 文件可以变得更小.这需要一些思考和实验.

    I have managed in simple examples to avoid using Jetifier, by manually resolving dependency conflicts between dependent modules and library modules. This way, APK file can turn out much smaller. It requires some thought, and experimentation.

    这一切都在 Gradle 构建文件的 dependencies 块中完成.我认为的原则是:从独立的库模块开始,使用属性加载所需的依赖项

    This is all accomplished int the Gradle build file's dependencies block. I think the principle is: starting with the independent library modules, load required dependencies with the property

    implementation
    

    但是在需要相同依赖项的依赖模块中,使用属性加载它们

    but in dependent modules that require the same dependencies, load them with the property

    compileOnly
    

    所以如果库模块和应用模块需要外部库

    So if the library module and the app module need the external library

    'androidx.recyclerview:recyclerview:1.1.0'
    

    库将在其依赖项

    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    

    而应用模块将具有

    compileOnly 'androidx.recyclerview:recyclerview:1.1.0'
    

    (如果两者都被列为implementation,则出现Duplicate class"错误;如果独立类缺少 compileOnly,则错误说明包不存在"的会发生.)

    (If both are listed as implementation, then "Duplicate class" errors occur; if the independent class is missing the compileOnly, errors saying a package that "does not exist" will occur.)

    此外,还可以通过使用 exclude 属性来定制 implementation 指令中链接的内容.

    Further, it is also possible to tailor just what is linked in the implementation directive by using exclude properties.

    这篇关于为 Wear OS 和普通应用程序构建的 Android Studio 项目,但共享源文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆