最近实现了把整个项目打包成aar供第三方App进行调用,过程是比较艰辛的,不过最终实现了,来记录一下,最让人头疼的就是项目中用到了butterknife,浪费的时间是最多的。
一 .完整项目打包aar 的流程
aar包简单介绍
aar包含所有资源,class,xml布局文件以及res资源文件全部包含。但是他不含有你在项目里引用的三方库.
捎带解释下jar.jar只包含了class文件与清单文件,不包含资源文件,如图片等所有res中的文件。所以如果想打包整个工程到新项目里用aar还是比较方便的.

第一步 修改build.gradle(app)
首先先将项目中的apply plugin: ‘com.android.application’ 替换成apply plugin: ‘com.android.library’.如下

//apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'
android {
    packagingOptions {
        exclude 'META-INF/maven/com.belerweb/pinyin4j/pom.xml'
        exclude 'META-INF/maven/com.belerweb/pinyin4j/pom.properties'
    }
    dexOptions {
        //incremental true
        javaMaxHeapSize "4g"
    }
    signingConfigs {
        config {
            storeFile file('/home/conf/com.cloudcns.debug.keystore')
        }
    }

第二步 修改manifests
将application里面的一些里的name,icon,label,theme等删掉 如下:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>

<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>

<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<application
    <!--android:name=".application.MyApplication"-->
    <!--android:allowBackup="true"-->
    <!--android:icon="@mipmap/ic_launcher"-->
    <!--android:label="@string/app_name"-->
    <!--android:roundIcon="@mipmap/ic_launcher_round"-->
    <!--android:supportsRtl="true"-->
    <!--android:theme="@style/AppTheme"-->
       android:allowBackup="true"
       android:supportsRtl="true">

然后再将manifests中的 主启动的intent-filter 删掉,如下:

<activity
        android:name=".activity.SplashActivity"
        android:screenOrientation="portrait"
        android:theme="@style/AppWelcome">
        <!--<intent-filter>-->
            <!--<action android:name="android.intent.action.MAIN"/>-->
            <!--<category android:name="android.intent.category.LAUNCHER"/>-->
        <!--</intent-filter>-->
    </activity>

如果项目中有加meta-data 也可以将meta-data 删掉 在你要引入的项目里重新加上.我这里直接注释掉了如下:

<!--<meta-data-->
        <!--android:name="UMENG_APPKEY"-->
        <!--android:value="596d9dbcf5ade420c8000e27" />-->
    <!--<meta-data-->
        <!--android:name="UMENG_MESSAGE_SECRET"-->
        <!--android:value="7e05110fc72e6803e8adcf08f199b0d7" />-->
    <!--<meta-data-->
        <!--android:name="UMENG_CHANNEL"-->
        <!--android:value="YingYongBao" />-->

第三步 如果你的项目里使用了butterknife,出现问题不要害怕
这个butterknife当时坑的我很惨,花了很长时间才解决掉.具体步骤如下:
之前测试了很多个butterknife 版本,只发现用8.4.0 好使.话不能说那么肯定.大家也可以用别的试试.首先在
buid.gradle(Project) 中增加
classpath ‘com.jakewharton:butterknife-gradle-plugin:8.4.0’.如下

image.png
其次在buid.gradle(app)中增加
apply plugin: ‘com.jakewharton.butterknife’

image.png

在下面dependencies 中增加:

compile 'com.jakewharton:butterknife:8.4.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'

之后,将项目里的R改成R2 因为R在library中报错.如下:

public class MainActivity extends BaseFragmentActivity implements MainHandler.UICallback, BaseHandler.UiCallback, View.OnClickListener, OtherHandler.PayCallback, OtherHandler.CommentCallback, NavigationView.OnNavigationItemSelectedListener {
    @BindView(R2.id.main_pager)
    NoSlidingViewPaper mainPager;
    @BindView(R2.id.tab1)
    LinearLayout tab1;
    @BindView(R2.id.tab2)
    RelativeLayout tab2;
    @BindView(R2.id.tab3)
    RelativeLayout tab3;
    @BindView(R2.id.tab4)
    LinearLayout tab4;
    @BindView(R2.id.tv_new_people)
    TextView tvNewPeople;
    @BindView(R2.id.nav_view)
    NavigationView navView;
    @BindView(R2.id.drawer_layout)
    DrawerLayout drawerLayout;
    @BindView(R2.id.iv_1)
    ImageView iv1;
    @BindView(R2.id.ll_bottom)
    LinearLayout llBottom;
    @BindView(R2.id.main_back)
    RelativeLayout mainBack;
    @BindView(R2.id.imageView1)
    ImageView imageView1;
    @BindView(R2.id.imageView2)
    ImageView imageView2;
    @BindView(R2.id.load_image)
    LinearLayout loadImage;

在就是很重要的

@OnClick({R2.id.textView, R2.id.button1, R2.id.button2, R2.id.button3, R2.id.image})
public void onViewClicked(View view) {

 int i = view.getId();
  if (i == R.id.textView) {
    
  } else if (i == R.id.button1) {
    
  } else if (i == R.id.button2) {
    
  } else if (i == R.id.button3) {
    
  } else if (i == R.id.tv) {
    
  }

}

library中的 不可以使用switch case,必须要用if else来的代替,否则空指针等其他错误。这里switch case 转 if else 教给大家一个简单的快捷键 Ait+Enter 对准switch 可以转换…我的项目里我是将所有 onViewClicked里的switch case 转成 if else了
上面的OnClick 里必须为R2 不然回报错.再就是下面的R 必须为R 不然你项目里的所有点击事件会不好使.这里非常重要.我在这里困了一天多

第四步 Assert资源获取
内嵌在其他应用中,原本APK中的Assert目录内的资源可能找不到。解决方法是,可以将Assert目录内的资源打包成一个ZIP文件放在 /RAW目录下。在项目初始化的时候,解压到指定目录下。使用的时候在AssertManager中使用绝对路径获取资源在于前端页面交互上,JS相关代码及资源一般也存放在Assert目录下,在webview.load()时,可以通过 file:/ 绝对路径 ,来加载PS:Assert 目录与 /raw 目录的区别:访问方式,目录结构,大小写,压缩方式等。

第五步 Application参数的传递问题
每一个Android App都有一个application context,这个参数需要工程传递给我们,调试的时候可以在壳工程的Manifest.xml中指定默认的Application.并在默认的Application中初始化aar.如下:

public class MyApplication extends MultiDexApplication implements CrashProcessHandler.ICoprocessor {

    public static AssetsDatabaseManager mg;
    public static boolean isKFSDK;
    public static Application app;
    public static Handler handler;

    @Override
    public void onCreate() {
        super.onCreate();
        handler = new Handler(){

        };
        app = this;

    }

    public static Context setInstance(Application appa){
        app=appa;
        return app;
    }
    public static Context getInstance() {
        return app;
    }

MyApplication .setInstance 是在你主工程的Application 里写的

第六步 打成aar
双击右侧的assembleRelease,如下图位置

Android aar中so库 android aar包含aar_android

成功后会在这里看到.如下:

Android aar中so库 android aar包含aar_android_02


然后就可以将app-release.aar 导入新工程里了!

到此为止完整项目打包aar算是完成了

二 .将aar 引到工程里
1.把aar文件放在一个文件目录内,比如就放在libs目录内 如下:

Android aar中so库 android aar包含aar_android_03

想要生成jniLibs 可以添加下面代码在build.gradle(app) android中:

sourceSets{
        main{
            jniLibs.srcDirs=['libs']
        }
    }
2.build.gradle(app)里添加如下内容:
    repositories {
        flatDir {
            dirs 'libs'
        }
    }

这样可以找到路径

3.dependencies 添加引用:
implementation (name: ‘app-release’,ext: ‘aar’)

aar 里面引用的三方库 在主项目上引用.比如:

implementation 'ca.barrenechea.header-decor:header-decor:0.2.6'
    implementation 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'
//    implementation 'com.google.zxing:core:3.2.1'
    implementation 'com.google.android.gms:play-services-gcm:9.4.0'
    implementation 'com.umeng.analytics:analytics:latest.integration'
    implementation 'com.jcodecraeer:xrecyclerview:1.3.2'
    implementation 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar'
    implementation 'com.android.support:cardview-v7:23.4.0'
    implementation('com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30') {
        exclude group: 'com.android.support'
    }

发现重复的可以以这样的方式移除掉:

implementation('com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30') {
    exclude group: 'com.android.support'
}

4.主项目的butterknife 需要跟aar 里面使用一样的版本.配置跟上面butterknife 一样.我就不重复写了.
5.manifests 设置
将原aar 项目里的activity ,service 等写在现在的manifests.不写的话会找不到activity/service .写的时候一定要带着包名,如下 :

<service
            android:name="包名.service.QianguanService"
            android:enabled="true"
            android:exported="true" />
     <activity
            android:name="包名.ui.EaseBaiduMapActivity"
            android:screenOrientation="portrait"
            android:theme="@style/horizontal_slide" />

meta-data 等也在manifests 写上:

<meta-data
        android:name="EASEMOB_APPKEY"
        android:value="xxxxxxxx" />

6.Application 上的设置
1.在Application 上将原Application 里的三方sdk 设置参数.写在主项目的Application中.
2.在Application上初始化aar包里的application.如下:

image.png

这样在项目里就可以使用aar包里的东西了.

7.主工程调aar 里的activity:
如下:

@OnClick({R.id.btn_login, R.id.btn_tourist_preview})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.btn_login:
                Intent in=new Intent();
                in.setClassName(this,"包名.activity.StartActivity");
                startActivity(in);
//                start(LoginActivity.class);
                finish();
                break;
            case R.id.btn_tourist_preview:
                start(MainActivity.class);
                finish();
                break;
        }
    }

这样完整的项目打包成aar 引用到新项目里就完成了.