开发一个第三方库的一般性和团队特定规则

目的

在于将可以重复使用的轮子共用,避免重复造轮子,从而提高生产力。

一般性规则

  1. 避免重复造轮子

    如果已有思路类似的轮子,请完善之而不是另起炉灶,除非对方的代码已经不堪维护。

  2. 谨慎设计 API

    规范化类和方法的命名,注意多参函数参数的位置,过时的 API 使用 @Deprecated 注解。

  3. 避免引入其他库

    当需要依赖第三方库时使用 compileOnly 而不是 implementation ,以避免将第三方库(特别是 support 包)打入其中,将其他第三方库的选择权交给集成者。

  4. 尽量用注解代替枚举

    注解 @IntDef@StringDef@Interface@Retention 了解一下。

  5. 资源文件加上特殊前缀

    第三方库的资源文件会跟集成者的相合并,因此需要在命名上独一无二。假定该库为 xxx-yyy ,那么所有资源文件建议加上前缀 xxx_yyy_

  6. 提供可插拔依赖的方案

    假定该库依赖于一个图片加载库,但不知集成者使用 Picasso 还是 Glide 或者其它图片加载库,这时可以使用 compileOnly 把它们都依赖进来(但不会打进最终的 aar 包),然后在代码中使用 Class.forName() (要捕获异常) 依次检测是否有对应的依赖,有则用之。

  7. 将Manifest中的参数变量化,并由 gradle.properties 控制

    // build.gradle
    defaultConfig{
        manifestPlaceholders = [
    		XXX_APP_KEY: "${XXX_APP_KEY}",
    	]
    }
    
    // gradle.properties
    #XXX
    XXX_APP_KEY=82d79e3cec5013
    
  8. 有多个相关依赖,做聚合依赖

    目的在于将依赖分组,这样可以当需时整组引入,当不需要时可以整组删除,不会留尾巴。下面以 retrofit2 依赖为例,进行依赖分组:

    ext.versions=[
      retrofit:'2.3.0',
    ]
    dependencies {
        implementation([
            "com.squareup.retrofit2:retrofit:${versions.retrofit}",
            "com.squareup.retrofit2:converter-gson:${versions.retrofit}",
            "com.squareup.retrofit2:adapter-rxjava2:${versions.retrofit}"
        ])
    }
    
  9. 当依赖中有两个以上需要使用相同的版本号时,请抽取到ext.versions 中,如上例的 retrofit 依赖,以便于版本维护。

  10. 根据需求考虑是否提供no-op

    如果开发的库只在 debug 模式中被使用,比如说 leakcanary 只在测试时进行内存泄漏检测,并不需要包含进生产包,那么可以提供生产的方法壳,里面为空实现。

  11. 仅仅在 debug 模式中引入代码

    对应仅仅在 debug 模式中被使用的库,请使用 debugImplementation 注解。

  12. 使用 JitPack 做库的托管仓库

    简单,快速

  13. 严格限制库的大小和方法数

  14. README 要讲清楚用途和用法

    要回答这几个问题:
    1. 有什么用?
    2. 怎样引入?
    3. 基本用法是什么?
    4. 支不支持自定义?
    
  15. 快速解决issue,多和提问者沟通

  16. 不断完善,坚持更新

特定于我们团队

  1. 使用 S3 Maven 发布第三库。

  2. 发布制品的规范。

    groupId 统一为 com.<group>.androidartifactId 统一使用前缀 <group>-

  3. 布局只用 XML 写,相关的字符串、颜色值期望可被自定义的统统抽取出来。

  4. 资源 ID 统一使用 artifactId- 替为_ 作为前缀。

  5. 整个库项目要包含两个模块:一是名为 app 的示例模块;二是名为 lib 的库依赖模块。

  6. app 的示例模块使用包名 com.sample.<库名>lib 模块使用包名com.<group>.<库名>

  7. 打包脚本统一放置在lib/script 中,并统一为:

    #!/bin/bash
    
    SCRIPT_DIR="$(dirname "${BASH_SOURCE:-$0}")"
    # ROOT_DIR=`readlink "$SCRIPT_DIR/../.."`
    ROOT_DIR=`python -c 'import os,sys;print os.path.realpath(sys.argv[1])' "$SCRIPT_DIR/../.."`
    
    cd $ROOT_DIR
    
    # detect gradle command
    GRADLE=`which gradle`
    GRADLE="${GRADLE:-$ROOT_DIR/gradlew}"
    
    "$GRADLE" clean \
              :lib:assembleRelease
              
     sleep 2s # wait the file being generated
    
     "$GRADLE" :lib:publish
    
  8. 每发布一次后请在代码中打上相应的 tag。

    假如发布了版本 1.0.1,那么请执行:

    git tag v1.0.1
    git push origin v1.0.1
    

参考

  1. 开发第三方库最佳实践 - 掘金
posted @ 2019-08-11 10:33  東籬老農  阅读(125)  评论(0编辑  收藏  举报