Android打包productFlavors 用法

最近项目中遇到了要使用opencv的情况,涉及到了abi兼容的选择。因为如果全部都适配的话,包很大,这样兼容那些用户数极少的cpu就很不划算,所以我只适配了armeabi-v7a这一个。但是今天在x64-v8a的模拟器上看的时候,提示我的library.so文件找不到,我记得这个应该是向下兼容的,但是出现这种情况很奇怪,于是我就在网上找了找答案。

解决方法:abiFilters

在app的gradle的defaultConfig里面加上这么一句

ndk {
    abiFilters  "armeabi-v7a"  // 指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,armeabi,arm-v8之类的so会被过滤掉)
}
 
 
  • 1
  • 2
  • 3

这句话的意思就是指定ndk需要兼容的架构,把除了v7a以外的兼容包都过滤掉,只剩下一个v7a的文件夹。用了这个方法之后,确实解决了问题。这就是解决方法。

具体分析

其实这个方法我开始是很奇怪的,我明明没有指定其他的兼容框架,为什么会需要一个过滤。我打来了apk的包,找到了里面的lib目录,发现里面有很多的兼容目录,然后看到里面目录里面的是一个fresco的.so文件。也就是说,fresco做了各个平台的兼容,所以它创建了各个兼容平台的目录。因为只要出现了这个目录,系统就只会在这个目录里找.so文件而不会遍历其他的目录,所以就出现了之前找不到.so文件的情况(因为其他目录没有我的.so文件)。

总结

为了决定最后适配的abi版本,我下载了排行前几名的app,然后打开之后发现,他们基本上只适配了一个armeabi,少数会再加上v7a。我了解到的情况是armeabi性能较差,但是兼容性最好,v7a对于浮点计算的cpu来说性能更好,不兼容不支持浮点运算的cpu。我想到的是目前的手机cpu绝大多数应该是支持浮点运算的,而且安卓从2.2开始就支持v7a,所以v7a的兼容性应该也不是问题。(不知道对不对,谁能明确一下的,恳请指正) 
无论如何,abiFilters还是应该添加的。





Android gradle的功能非常强大,用这篇文章简单介绍一下gradle中productFlavors的用法。productFlavors顾名而思义,就是用于定义产品的特性,这是每个产品不同的地方。有了它我们可以用同一套代码创建不同的产品。设置productFlavors的方法如下: 
在build.gradle中加入productFlavors结构

android{
    #......
    productFlavors{
        productA{
            #这里定义产品A的特性
        }

        productB{
            #这里定义产品B的特性
        }

        #更多产品 ...
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这样在最终编译的时候(终端运行gradle build命令),就会编译出多个产品的APK出来,平时调试的时候,一般通过设置一个产品来调试,设置在AndroidStudio左下角的Build Variants菜单中: 
这里写图片描述 
菜单中会有productADebug,productARelease,productBDebug等,它们是productFlavors和buildTypes中的两两组合。选中其中一个,调试的时候就是使用这个产品。

主要的应用场景如下:

不同产品,不同包名

    productFlavors{
        productA{
            applicationId "com.crazyman.product.a"
            versionName "version-a-1.0"
        }

        productB{
            applicationId "com.crazyman.product.b"
            versionName "version-b-1.0"
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

通过为不同的产品设置不同的applicationId可以在编译后产生不同包名的APK。用途很多,比如同时在手机上安装测试,生产环境的APK。

不同产品,不同渠道号

因为国内应用市场太多,很多时候投放推广的时候需要追踪应用市场的数据,所以为每个应用市场打一个不同的包是有需要的,应用市场的包,通常叫做渠道包,区别一般只有一个ID(渠道号)不一样,这个ID是保存在AndroidManifest文件中,所以在编译时需要动态修改AndroidManifest中的数据,这个用manifestPlaceholders就可以搞定了:

    productFlavors{
        productA{
            manifestPlaceholders = [UMC:"product-a"]
        }

        productB{
            manifestPlaceholders = [UMC:"product-b"]
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

然后在AndroidManifest中使用:

<meta-data android:name="UMENG_CHANNEL" android:value="${UMC}"/>
 
 
  • 1
  • 1

不同产品,不同库

有时候APP的运行环境不同,使用的库也要不一样,一般的做法是把所有的库都添加进来,然后跟据运行环境判断一下,再调用相应的库。另外一种做法是为不同的产品编译不同的库,产品A只编译自己需要库,不需要编译对自己无用的库。

dependencies {
    # ....
    productACompile 'io.reactivex.rxjava2:rxjava:2.0.1'
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

不同产品,不同代码

库可以不一样,代码当然也可以不一样了,gradle中有一个source set的概念,对于不同的产品,可以设置不同的source set。通常,创建工程后,AndroidStudio默认帮我们创建了应用于所有产品的代码集main,它的对应的目录是src/main,我们也可以创建每个产品特有的代码集src/productA,src/productB这样,名字和产品名字是对应的。在编译的时候,默认会将这些代码集加入编译,这样就实现了不同产品,不同代码。这种用法也是非常广的,比如两个产品实现同样的接口,但是底层实现不一样。 
这里写图片描述

不同产品,不同资源

这个用法其实和上面是一样的,代码集中可以定义资源,这样就做到了不同的产品,使用不同的资源,同样可以定义不同的AndroidManifest文件,比如申请不同的权限之类的。

参考链接

https://developer.android.com/studio/build/build-variants.html 
https://developer.android.com/studio/build/manifest-build-variables.html


  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值