【问题标题】:Android Instant App: How to create URL addressable modules?Android Instant App:如何创建 URL 可寻址模块?
【发布时间】:2017-06-24 18:45:51
【问题描述】:

Google 最近更新了有关即时应用的文档:Prepare your app

除了 3. Refactor your app, if necessary之外,大部分点都清楚了。

他们建议零售模块,例如浏览、搜索、商品详情和结帐。

问题:如何将应用拆分为功能齐全且可通过 URL 寻址的模块?

我确实看到了几个问题:

  • 如果我们使用 dagger、butterknife 等库...所有模块都将依赖于其他模块
  • 如果我们的模块根据需要包含(视图),如何在不导入此模块的情况下实现到另一个视图(从另一个模块)的转换?

有人可以在黑暗中照亮吗?谢谢!

【问题讨论】:

  • if we use libraries like dagger, butterknife, ... all modules would be dependant on other modules - 一点也不。他们为什么要这样做?我最近对大量使用 Dagger 和 ButterKnife 的庞大代码库进行了这样的重构,可以说——这对我来说不是问题。查看我的答案以获取更多详细信息,并让我知道。你不清楚。

标签: android android-studio android-gradle-plugin android-build android-instant-apps


【解决方案1】:

Instant Apps 所需的适当模块分离可以通过以下步骤轻松完成:

  1. 创建一个共享模块,其中包含应跨功能模块共享的代码和资源。
  2. 为每个主要功能创建几个功能模块(在 Google 提供的示例中:浏览、搜索、项目详细信息和结帐)。这些模块可以依赖于 p.1 中创建的共享模块,但它们之间不应相互了解。
  3. 要从不同的模块启动一个活动,使目标活动的 URL 可寻址,并通过隐式意图启动它。谷歌suggests 使用应用链接。
  4. 要构建您的常规 Android 应用,请创建一个依赖于功能模块的应用模块。
  5. 一旦 Google 向公众发布其 Android InstantApp SDK,您就可以构建您的 Instant Apps(每个功能一个)。

【讨论】:

    【解决方案2】:

    Instant Apps 现已向开发者开放,请参阅official docs

    总而言之,所有免安装应用都至少具有所谓的基本功能模块,其中包含整个免安装应用的通用代码。最重要的是,Instant Apps 可以选择拥有 1 个或多个依赖于基本功能模块的附加功能库。每个功能模块都可以有自己的 URL 可寻址的入口点,尽管功能模块本身不需要相互依赖。如果一个需要调用另一个,可以通过基于 URL 的 Intent 来完成。

    来自 docs 网站的图表有点帮助:

    所有功能模块都使用新的com.android.feature 插件,它的使用方式与传统的com.android.library 插件在您在Android 项目中的使用方式相似,因此library docs 可以用作一个参考。不同之处在于,与可安装应用程序模块一起使用时会输出一个常规的 AAR 文件,与新的 Instant App 模块一起使用时会输出一个功能 APK。

    【讨论】:

      【解决方案3】:

      考虑这个图表。

      问:如何将应用拆分成功能齐全且可通过 URL 寻址的模块?

      基础模块:包含您的应用所需的所有常用资源。所以在我们的例子中,来自 feature1 和 feature2 的所有活动都将使用来自基本模块的共享资源。它可能有像 dagger、butterknife 这样的库。

      现在是时候将您的整个应用程序分解为一个称为功能的较小单元了。单个功能可能包含多个活动,这些活动可能只是让您了解您的应用程序或完成一个促使用户安装该应用程序的目标。现在,它完全取决于您要向用户提供什么东西,并坚持他们下载您的应用程序。

      Feature1:所以我们将应用拆分为 feature1 和 feature2。在此功能中,我们让用户搜索和浏览项目。 每当用户单击项目时,我们需要从 feature2 加载项目详细信息,因此从浏览活动中单击项目,我们将调用类似

      Intent intent = new Intent(Intent.ACTION_VIEW,
                      Uri.parse("https://yourdomain.com/itemdetail"));
              intent.setPackage(getPackageName());
              intent.addCategory(Intent.CATEGORY_BROWSABLE);
              startActivity(intent);
      

      因为:feature1中的Activity1不能直接调用feature2中的Activity2。为此,您必须从 activity1 请求 activity2 的 URL 地址。

      功能 2: 现在,Feature2 已加载到免安装应用中,因此我们现在可以查看项目详细信息活动。

      注意:您还应该在拆分应用功能时考虑您的功能大小,因为每个功能的大小不得超过 4MB,否则在将 apk 上传到 Play 商店时会进行验证。

      【讨论】:

        【解决方案4】:

        我不确定我是否误解了您的问题,但我会尝试解决它。对于下面的解释,我将多次引用this code sample by Google。我高度建议克隆该 repo 并使用它,因为我认为它会回答您的问题。

        如果我们使用 dagger、butterknife 等库...所有模块都将依赖于其他模块

        正如其他人所提到的,您的所有功能都将使用的任何库都将进入您的基本功能。

        如果我们的模块根据需要包含(视图),如何在不导入此模块的情况下实现到另一个视图(从另一个模块)的转换?

        This answer 涵盖了它的概述 - 但这部分似乎是你问题的根源,所以我会尝试更深入地挖掘。

        假设 Feature1 (BrowseActivity) 想要打开 Feature2 (ItemDetailActivity)。而不是 Feature1 直接调用 startActivity(ItemDetailActivity.class),它必须使用下面的方法调用(这是因为 Feature1 无权访问 Feature2 的 ItemDetailActivity.class,因为它们不相互依赖)。 Here is the code sample provided by Google

        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com/itemdetail"));
        intent.setPackage(getPackageName());
        intent.addCategory(Intent.CATEGORY_BROWSABLE);
        startActivity(intent);
        

        现在缺少的部分是在 Feature2 的 AndroidManifest 中,您需要声明 ItemDetailActivity 正在侦听 https://example.com/itemdetail 链接。 Here is the relevant code sample from Google

        <activity android:name=".ItemDetailActivity">
            <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter android:autoVerify="true">
              <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.DEFAULT" />
              <category android:name="android.intent.category.BROWSABLE" />
              <data android:scheme="http" />
              <data android:scheme="https" />
              <data android:host="example.com" />
              <!-- IMPORTANT -->
              <data android:pathPrefix="/itemdetail"/>
            </intent-filter>
            <meta-data
              android:name="default-url"
              android:value="https://www.example.com/itemdetail" />
        </activity>
        

        如需了解更多信息,请阅读Digital Asset Links 以及一般Deep Linking

        【讨论】:

          【解决方案5】:

          我认为功能模块提出了一切应该模块化的概念。最后,每个可能的功能都分离到功能模块中。

          我从这个talk开始了解项目结构的新方式。 这让我明白了一点。

          如果我们创建功能模块并想要链接到功能基础模块,我们可能需要删除未使用的 androidTest testres 资源。

          同时创建一个新结构的简单项目here

          在这个 repos 上,尝试从头开始以下文档及以上以从应用程序模块更改为功能模块并将即时应用程序模块添加到代码库中。

          【讨论】:

          猜你喜欢
          • 2019-06-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-28
          • 1970-01-01
          相关资源
          最近更新 更多