一 . 背景
公司一直在做一個的項目,需要上架,因為某種原因上不上去.結(jié)果出了一個主意想把以前已死的項目作為馬甲包,幫助新項目上架.這個任務(wù)給我了.我一時間想到的解決方案就是把老項目打包成aar包,放到新項目里.其中遇見了很多的坑,在此做一下記錄.
一 .完整項目打包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"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.saileikeji.sych">
<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,出現(xiàn)問題不要害怕
這個butterknife當時坑的我很慘,花了很長時間才解決掉.具體步驟如下:
之前測試了很多個butterknife 版本,只發(fā)現(xiàn)用8.4.0 好使.話不能說那么肯定.大家也可以用別的試試.首先在
buid.gradle(Project) 中增加
classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0'.如下
其次在buid.gradle(app)中增加
apply plugin: 'com.jakewharton.butterknife'
在下面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 轉(zhuǎn) if else 教給大家一個簡單的快捷鍵 Ait+Enter 對準switch 可以轉(zhuǎn)換..我的項目里我是將所有 onViewClicked里的switch case 轉(zhuǎn)成 if else了
上面的OnClick 里必須為R2 不然回報錯.再就是下面的R 必須為R 不然你項目里的所有點擊事件會不好使.這里非常重要.我在這里困了一天多
第四步 Assert資源獲取
內(nèi)嵌在其他應(yīng)用中笆环,原本APK中的Assert目錄內(nèi)的資源可能找不到攒至。解決方法是,可以將Assert目錄內(nèi)的資源打包成一個ZIP文件放在 /RAW目錄下躁劣。在項目初始化的時候迫吐,解壓到指定目錄下。使用的時候在AssertManager中使用絕對路徑獲取資源在于前端頁面交互上账忘,JS相關(guān)代碼及資源一般也存放在Assert目錄下志膀,在webview.load()時,可以通過 file:/ 絕對路徑 鳖擒,來加載PS:Assert 目錄與 /raw 目錄的區(qū)別:訪問方式溉浙,目錄結(jié)構(gòu),大小寫蒋荚,壓縮方式等戳稽。
第五步 Application參數(shù)的傳遞問題
每一個Android App都有一個application context,這個參數(shù)需要工程傳遞給我們圆裕,調(diào)試的時候可以在殼工程的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
雙擊右側(cè)的assembleRelease广鳍,如下圖位置
成功后會在這里看到.如下:
然后就可以將app-release.aar 導(dǎo)入新工程里了!
到此為止完整項目打包aar算是完成了
二 .將aar 引到工程里
1.把aar文件放在一個文件目錄內(nèi),比如就放在libs目錄內(nèi) 如下:
想要生成jniLibs 可以添加下面代碼在build.gradle(app) android中:
sourceSets{
main{
jniLibs.srcDirs=['libs']
}
}
2.build.gradle(app)里添加如下內(nèi)容:
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'
}
發(fā)現(xiàn)重復(fù)的可以以這樣的方式移除掉:
implementation('com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30') {
exclude group: 'com.android.support'
}
4.主項目的butterknife 需要跟aar 里面使用一樣的版本.配置跟上面butterknife 一樣.我就不重復(fù)寫了.
5.manifests 設(shè)置
將原aar 項目里的activity ,service 等寫在現(xiàn)在的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 上的設(shè)置
1.在Application 上將原Application 里的三方sdk 設(shè)置參數(shù).寫在主項目的Application中.
2.在Application上初始化aar包里的application.如下:
這樣在項目里就可以使用aar包里的東西了.
7.主工程調(diào)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 引用到新項目里就完成了.