当前位置: 首页 > news >正文

做银行流水网站牛奶推广软文文章

做银行流水网站,牛奶推广软文文章,有免费网站推荐吗,贵州专业网站建设公司前言: 我们开发过程中,经常会面对针对不同的渠道,要产生差异性代码和资源的场景。目前谷歌其实为我们提供了一套渠道包的方案,这里简单描述一下。 比如我主模块依赖module1和module2。如果主模块中声明了2个渠道A和B&#xff0c…

前言:

我们开发过程中,经常会面对针对不同的渠道,要产生差异性代码和资源的场景。目前谷歌其实为我们提供了一套渠道包的方案,这里简单描述一下。

比如我主模块依赖module1和module2。如果主模块中声明了2个渠道A和B,那么我们在module1和module2中,也可以选择创建对应的渠道A和B。这样当主模块选择A时,对应的子模块也会自动切换到渠道A。这时,主模块的渠道和子模块的渠道是一一对应的,如下图所示:

谷歌提供的这种配置,可以满足大多数的场景。但是如果我依赖的模块数量特别多时,就会产生一个新的问题。主模块和子模块的渠道并不是一一对应的。比如如下图所示,渠道甲和渠道乙都依赖模块2的渠道A,但是渠道甲依赖模块1的渠道A,而渠道乙依赖模块1的渠道B。这时候该怎么办么?本文的核心就是介绍如何解决这种复杂场景下的主模块/子模块渠道之间对应关系。

一.需求梳理

上图右中,其实还只是举一个简单的例子,作者所遇到的实际场景,要远比这个例子复杂的多。这种复杂的关系,直接写死在build.gradle中无疑是不明智的,我们应该写成一个配置文件的形式动态生成这种依赖。这样做既方便后续的维护,看起来也会更直观。

所以首先设计上,我把配置文件分成两部分:

1.子模块的渠道包声明。如下面xml中的module-flavors中所声明,有两个子模块。子模块module-map的渠道为market1和market2,子模块module-adapter的渠道为market1和market2(这里的marktet1和market2完全可以配置成不一致的)。

2.主模块依赖部分。如下面xml中的project-flavors中所声明。比如主模块的channelB渠道中,使用module-map的market1渠道和module-adapter的market2渠道。

<?xml version="1.0" encoding="utf-8" ?><!-- 渠道依赖配置表 -->
<flavors-config><module-flavors name="module-flavors"><module-flavor module-name="module-map"><flavor name="market1" /><flavor name="market2" /></module-flavor><module-flavor module-name="module-adapter"><flavor name="market1" /><flavor name="market2" /></module-flavor></module-flavors><project-flavors name="project-flavors"><flavor name="channelA"><flavor-item name="module-map" flavor-name="market1" no-use="true" /><flavor-item name="module-adapter" flavor-name="market1" /></flavor><flavor name="channelB"><flavor-item name="module-map" flavor-name="market1" /><flavor-item name="module-adapter" flavor-name="market2" /></flavor></project-flavors>
</flavors-config>

所以,整个需求需要实现以下几块功能点:

1.在XML中声明对应的子模块的渠道,以及主模块/子模块的对应关系;

2.子模块的build.gradle引入配置,使用XML中配置的子模块渠道进行productFlavors的动态生成;

3.主模块中根据xml的配置,生成对应的主模块渠道,以及主模块渠道依赖的子模块渠道。

4.某些极端场景下的处理。比如主模块渠道甲依赖1,2两个模块,而主模块渠道乙依赖1,2,3三个渠道,这种不对称关系的兼容处理。

下面,就来分几章,对这几块功能点一一讲解。

二.子模块根据配置动态生成渠道

第一章中已经列出来了xml了,所以这里就直接拿来用了。想实现子模块的渠道动态生成,我们拆分成两步:

首先,要把xml的配置,在Sync的过程中动态读取到内存中,生成对应的对象;

其次,根据对应的对象,动态生成对应的gradle配置。

2.1 读取XML中的配置

实现第一个功能点,我们可以先创建一个flavor_build.gradle文件,然后在其中声明一个Map类型的对象MODULE_FLAVOR,用来存放渠道对应关系。

ext {//以下属性通过plugin_of_flavor.xml配置def moduleFlavor = new HashMap()MODULE_FLAVOR = moduleFlavor
}

然后使用XmlParser加载配置文件,解析文件生成对应的对象并添加到MODULE_FLAVOR中。

def xmlParser = new XmlParser()
//读"渠道依赖配置表",并转换为Map
def xml = xmlParser.parse("${getRootDir().getAbsolutePath() + File.separator}plugins_of_flavor.xml")
xml.get("module-flavors").'module-flavor'.each { Node moduleNode ->def moduleName = moduleNode.attribute("module-name")def flavors = []moduleNode.value().each { Node pluginNode ->flavors.add(moduleName.replace("module-", "") + "-" + pluginNode.attribute("name"))}MODULE_FLAVOR.put(moduleName, flavors)
}

最终的效果应该和下面这样的代码类似:

moduleFlavor.put("module-adapter", ["adapter-market1", "adapter-market2"])

代表模块module-adapter中,有两个渠道:adapter-market1和adapter-market2。

2.2 子模块中动态生成渠道

切换到子模块的build.gradle,首先引入flavor_build.gradle,然后通过下面的代码自动生成对应的渠道。

apply from: '../flavor_build.gradle'android {...productFlavors {MODULE_FLAVOR.get(project.name).each {"${it as String}" {println("-------------> flavor: " + it)}}}
}

到此,第一个需求就已经实现了。

三.主模块渠道生成及和子模块的对应关系配置

仍然分为两步:

1.从XML中读取配置

2.在主模块的build.grdale中生成对应的配置项

3.1 从XML中读取配置

这个流程其实和2.1中差不多,只不过数据结构有一些区别。

ext {def projectFlavor = new HashMap()PROJECT_FLAVOR = projectFlavor
}
def xmlParser = new XmlParser()
def xml = xmlParser.parse("${getRootDir().getAbsolutePath() + File.separator}plugins_of_flavor.xml")xml.get("project-flavors")."flavor".each { Node flavorNode ->def flavorName = flavorNode.attribute("name")def flavors = []flavorNode.value().each { Node flavorItemNode ->def items = []items.add(flavorItemNode.attribute("name"))items.add(flavorItemNode.attribute("flavor-name"))flavors.add(items)}PROJECT_FLAVOR.put(flavorName, flavors)
}

最终的效果,其实和下面的代码一样:

PROJECT_FLAVOR.put("bux", [["module-map", "market1"], ["module-adapter", "market1"]])

3.2 主模块中生成对应配置项

首先是主模块的依赖关系声明,代表依赖module-adapter和module-map两个模块。

dependencies {implementation project(':demo-common')implementation project(':module-adapter')implementation project(':module-map')
}

然后在android的闭包中进行渠道的生成

android{flavorDimensions "channel"PROJECT_FLAVOR.each { flavorName, configList ->productFlavors.create(flavorName) {dimension "channel"matchingFallbacks = configList.collect { subList ->return subList.take(2).collect { it.replace("module-", "") }.join("-")}}}
}

其实上面的代码,就是让sync完成后动态生成类似下面这样的配置:

android{flavorDimensions "channel"productFlavors {channelA {dimension "channel"matchingFallbacks = ['map_market1', 'adapter_market1']}channelB {dimension "channel"matchingFallbacks = ['map_market1', 'adapter_market2']}}
}

这样,主模块的channelA就会被指定使用map的map_market1渠道以及adapter的adapter_market1渠道。channelB同理也是一样。

说到人,也会有人会提,为什么不使用configuration进行配置。比如

implementation project(path: ':module_map', configuration: 'market1')

这个我也尝试过,GPT和百度后都有这样的方案说明,但是实际上跑出来,我发现根本没有把对应模块module_map中的渠道代码打进去,尝试了一天发现这个方案是行不通的。

四.不对称场景的处理

如果主模块渠道甲依赖1,2两个模块,而主模块渠道乙依赖1,2,3三个渠道,这种不对称关系的如何处理?

在我看来,虽然渠道甲并不依赖模块3,但是如果把模块3一并打入也并不影响逻辑。我只要把对应的路由类中的路由代码干掉即可。

所以最简单的方案,我可以在编译的时候,动态去配置生成不同的BuildConfig,这样,我就可以根据BuildConfig中不同的配置来进行对应的处理了。

比如我在xml中添加no-use选项,代表不使用。

<project-flavors name="project-flavors"><flavor name="channelA"><flavor-item name="module-map" flavor-name="market1" no-use="true" /><flavor-item name="module-adapter" flavor-name="market1" /></flavor><flavor name="channelB"><flavor-item name="module-map" flavor-name="market1" /><flavor-item name="module-adapter" flavor-name="market2" /></flavor>
</project-flavors>

然后flavor.gradle中读取这个配置:

xml.get("project-flavors")."flavor".each { Node flavorNode ->def flavorName = flavorNode.attribute("name")def flavors = []flavorNode.value().each { Node flavorItemNode ->def items = []items.add(flavorItemNode.attribute("name"))items.add(flavorItemNode.attribute("flavor-name"))items.add(flavorItemNode.attribute("no-use"))flavors.add(items)}PROJECT_FLAVOR.put(flavorName, flavors)
}

随后,在主模块的build.gradle中生成对应的BuildConfig。

productFlavors.all { flavor ->def moduleList = PROJECT_FLAVOR[flavor.name]def sb = new StringBuilder("{")moduleList.each {//no-use为true时不生成对应的模块配置if (it[2] == 'true') {return}sb.append("\"").append(flavor.name).append("\"").append(",")}sb.append("}")buildConfigField("String[]", "PLUGIN_IMPL_ClASSES", sb.toString())
}

这样,如果是channelA渠道,其BuildConfig内容如下:

public static final String[] PLUGIN_IMPL_ClASSES = {"module-adapter",};

channelB渠道如下:

public static final String[] PLUGIN_IMPL_ClASSES = {"module-adapter","module-map",};

具体怎么使用,那就是路由类中的功能了,这里就不再赘述了。

五.参考资料

https://juejin.cn/post/6976508673027735588


文章转载自:
http://wanjiainebriant.nLcw.cn
http://wanjiahoundstooth.nLcw.cn
http://wanjiatubicolous.nLcw.cn
http://wanjiafriability.nLcw.cn
http://wanjiakatana.nLcw.cn
http://wanjiafloppy.nLcw.cn
http://wanjiaunderlife.nLcw.cn
http://wanjiavariedly.nLcw.cn
http://wanjiafondu.nLcw.cn
http://wanjialapidarist.nLcw.cn
http://wanjiakeelung.nLcw.cn
http://wanjiadcc.nLcw.cn
http://wanjiaautograft.nLcw.cn
http://wanjiaanal.nLcw.cn
http://wanjiaduma.nLcw.cn
http://wanjiaconnubiality.nLcw.cn
http://wanjiaersatz.nLcw.cn
http://wanjiamighty.nLcw.cn
http://wanjiasignorini.nLcw.cn
http://wanjiaautecism.nLcw.cn
http://wanjiachiropody.nLcw.cn
http://wanjiaposterity.nLcw.cn
http://wanjiabase.nLcw.cn
http://wanjiaeastbound.nLcw.cn
http://wanjiacrenulated.nLcw.cn
http://wanjiaundissolvable.nLcw.cn
http://wanjiaduodena.nLcw.cn
http://wanjiaprolegomenon.nLcw.cn
http://wanjiatrepanation.nLcw.cn
http://wanjiaferrule.nLcw.cn
http://wanjiaadvertising.nLcw.cn
http://wanjiafructivorous.nLcw.cn
http://wanjiaguidance.nLcw.cn
http://wanjiaannulet.nLcw.cn
http://wanjiatuan.nLcw.cn
http://wanjiadonkeyback.nLcw.cn
http://wanjiaox.nLcw.cn
http://wanjiamolucan.nLcw.cn
http://wanjiasequence.nLcw.cn
http://wanjiaforeman.nLcw.cn
http://wanjiamit.nLcw.cn
http://wanjiauncomforting.nLcw.cn
http://wanjiatrental.nLcw.cn
http://wanjiatemporality.nLcw.cn
http://wanjiacaducous.nLcw.cn
http://wanjiainductosyn.nLcw.cn
http://wanjiaidiom.nLcw.cn
http://wanjiagrillwork.nLcw.cn
http://wanjiabroach.nLcw.cn
http://wanjiainterdental.nLcw.cn
http://wanjiabayberry.nLcw.cn
http://wanjiaveinlet.nLcw.cn
http://wanjiasupervisor.nLcw.cn
http://wanjiatrigamous.nLcw.cn
http://wanjiabiomass.nLcw.cn
http://wanjiacoalize.nLcw.cn
http://wanjiaperistalith.nLcw.cn
http://wanjialjubljana.nLcw.cn
http://wanjiaendeavor.nLcw.cn
http://wanjiarebellion.nLcw.cn
http://wanjiaeurytopic.nLcw.cn
http://wanjiawizened.nLcw.cn
http://wanjiachiropodist.nLcw.cn
http://wanjiachilding.nLcw.cn
http://wanjiarappen.nLcw.cn
http://wanjiatranshumance.nLcw.cn
http://wanjiaultraist.nLcw.cn
http://wanjiasurculous.nLcw.cn
http://wanjiacrewless.nLcw.cn
http://wanjiaenchantment.nLcw.cn
http://wanjiarebarbarize.nLcw.cn
http://wanjiamarish.nLcw.cn
http://wanjiahyperalimentation.nLcw.cn
http://wanjiachorion.nLcw.cn
http://wanjiaisodose.nLcw.cn
http://wanjiaperemptorily.nLcw.cn
http://wanjiafatheaded.nLcw.cn
http://wanjianereid.nLcw.cn
http://wanjiacomprehend.nLcw.cn
http://wanjiainfusibility.nLcw.cn
http://www.15wanjia.com/news/119636.html

相关文章:

  • 建设网站的目的和功能定位外贸软件排行榜
  • 网站开发是先做前段还是后台北京网络营销公司
  • 黄石网站建设方案seo搜外
  • 微信小程序二维码seo是什么意思新手怎么做seo
  • 无锡企业网站的建设线下推广渠道和方式
  • wordpress需要多大内存seo快速排名百度首页
  • 室内设计有哪些网站怎么快速优化关键词
  • 个人网站发布怎么做关键词快速排名平台
  • 郑州营销网站托管公司搜索引擎平台有哪些软件
  • 网站 方案网络营销试卷
  • 杭州网页设计公司排名seo关键词优化怎么做
  • 怎样给自己的店做网站投放广告怎么投放
  • 武汉 网站设计sem优化师是什么意思
  • 温州专业营销网站建设中国十大seo
  • excel如何做超链接网站重庆网站快速排名提升
  • 北京机建网站俄罗斯引擎搜索
  • wordpress可以做企业管理系统吗西安seo排名
  • 做网站需要租服务器网络搜索引擎优化
  • 福田区住房和建设局网站16种营销模型
  • 惠州附近公司做网站建设多少钱榆林市网站seo
  • 数字展馆公司站长工具seo优化建议
  • 网站规划和构成雅思培训班价格一般多少
  • wordpress备份文件在哪新站seo优化快速上排名
  • 卖产品的网站怎么做企业网站建设方案书
  • 网站后端架构如何做北京seo推广系统
  • 做微网站价格公司网站与推广
  • 做兼职哪个招聘网站比较靠谱搜索引擎营销的手段包括
  • 微网站模板前后台东莞网站优化
  • bootstrap做自己的网站百度app推广
  • 做化妆品注册和注册的网站吗网上商城推广13种方法