Android 將Activity及其他類打包成jar包供第三方呼叫
在開發java工程時,一個專案可能分為多個模組,為了實現模組間的解耦和獨立,提高模組的複用性,通常將專案按模組分為多個java工程進行開發,最後通過jar包等工程依賴的方式實現系統整合,提高模組的耦合和複用。
現在開發Android專案通過實踐和總結,發現這種方式特別有必要,比如開發一個android端的視訊播放功能,肯定有播放和下載模組,如果不分開放在一個工程裡面不斷的新增新的功能,產品的每一個研發都不斷的新增修改功能,最後維護越來越難,bug越來越多,並相互推諉,這種方式能避免這種情況,此為有點一。其二呢,下載模組是很多APP都會用到的模組,將其獨立出來不斷的完善和優化,可以變成一個元件給不同的APP使用,這就提高了模組的程式碼的解耦,提高的複用性,提高的工作效率,好處大大的哦。
由於Android的特殊性,android不僅有java檔案還有res檔案,需要研究如何將資原始檔以及Activity檔案打包成jar檔案供其他專案呼叫,最終多方嘗試,找到如下兩種解決方案。
方案一:
根據Android的官方文件,將其中一個專案設定為引用庫,在另一個專案中新增這個庫的引用。
簡單的做法是
在被引用專案TestJar中的project.properties中新增一行
android.library=true
在引用的專案TestMain的project.properties中新增
android.library=false android.library.reference.1=../TestJar
其中1表示引用包的序號,“../TestJar”表示引用專案的路徑
在Eclipse中操作具體做法如下:
- 把普通的android project設定成庫專案
庫專案也是一個標準的Android專案,因此你先建立一個普通的Android專案,這個專案可以起任何的名稱,任何的包名,設定其他需要設定的欄位等。
接著把專案設定成庫專案,步驟如下:
1)在Package Explorer中,滑鼠右鍵專案資料夾(TestJar),點選Properties。
2)在Properties視窗選擇”Android“,Library屬性顯示在右下邊。
3)把”is Library“單選框選上,在點選Apply。
4)點選OK關閉Properties。
這時,這個專案就變成庫專案了,當然純的java專案也可以變成庫專案,非常簡單,執行上面四步就OK了。其他程式專案就可以引用這個庫專案了。
引用庫專案
如果你開發的應用程式想要呼叫庫專案中的程式碼和資源,也easy哦,引用步驟如下:
1)在Package Explorer中,滑鼠右鍵專案資料夾(TestJar),點選Properties。
2)在Properties視窗選擇”Android“,Library屬性顯示在右下邊。
3)點選Add,打開了Project Selection對話方塊。
4)從可用的庫專案列表中選擇要新增的庫專案,點選OK。
5)對話方塊關閉之後點選Apply,(在Properties視窗)。
6)點選OK,關閉Properties視窗。
完成以上六步,Eclipse會重建專案,把庫專案中的內同包含進去。
- 如果你想增加多個庫專案的引用,使用up和down可以設定他們的相對的優先順序和合並順序。工具在合併引用的庫的時候順序是從低優先順序(列表的下面)到高優先順序(列表的上面)。 如果不只一個庫定義了相同的資源ID,這個工具選擇資源時會選擇高優先順序的資源。應用程式自身擁有最高的優先順序。
方案二:
通過匯出JAR包的方式供給其他專案去引用,沒有資源包就不多說了直接匯出jar包就可以直接引用,下面說一下在有資源包存在的時候打包Jar及引用方式。
實現步驟:
- 我們新建一個工程TestJar,這個就是等下我們要打包成jar工程
- 注意:MResource這個類很重要,主要是它的作用,利用反射根據資源名字獲取資源ID(其實系統也自帶了根據資源名字獲取資源ID的方法getResources().getIdentifier("main_activity", "layout", getPackageName());第一個引數是資源的名字,第二個引數是資源的型別,例如layout, string等,第三個是包名字)
- MRsource.java程式碼如下:
import android.content.Context; /** * 根據資源的名字獲取其ID值 * * @author yangzy */ public class MResource { public static int getIdByName(Context context, String className, String name) { String packageName = context.getPackageName(); Class r = null; int id = 0; try { r = Class.forName(packageName + ".R"); Class[] classes = r.getClasses(); Class desireClass = null; for (int i = 0; i < classes.length; ++i) { if (classes[i].getName().split("\\$")[1].equals(className)) { desireClass = classes[i]; break; } } if (desireClass != null) id = desireClass.getField(name).getInt(desireClass); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } return id; } }
-
import android.content.Context; public class Statistics { public static Statistics mStatistics; public static Context mContext; public static Statistics getInstance() { if (mStatistics == null) { mStatistics = new Statistics(); } return mStatistics; } public void init(Context context) { this.mContext = context; System.out.println("--Statistics---init--"); } public void Login(int num) { System.out.println("--Statistics---" + num); } }
- TestUtilJar.java實現比較簡單一個圖片點選後彈出一個Toast
import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; import android.widget.Toast; public class TestUtilJar extends Activity { private ImageView imageView; private Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(MResource.getIdByName(getApplication(), "layout", "jar_activity_main")); context = this; imageView = (ImageView) findViewById(MResource.getIdByName(getApplication(), "id", "jar_imageView")); imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Toast.makeText( context, "jar = " + getApplication().getString( MResource.getIdByName(getApplication(), "string", "jar_test_name")), Toast.LENGTH_SHORT).show(); } }); } }
- 佈局檔案如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00eeff" tools:context=".MainActivity" > <ImageView android:id="@+id/jar_imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginBottom="80dp" android:src="@drawable/photo" /> </RelativeLayout>
- 將TestJar以Jar包形式匯出,出去一切資原始檔,只匯出原始碼
6、將匯出的testjar1.jar匯入到要引用的工程中,先複製到libs下面
最關鍵一步,將TestJar中引用到的資原始檔全部拷貝到TestMain中去,這樣就可以順利的引用資原始檔了,還有要用到Jar包中的Activity也需要再TestMain的AndroidManifest.xml配置對應包名的Activity。
- 在TestMain中引用
package com.example.testmain; import com.example.testjar.TestUtilJar; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener { private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button1); button.setOnClickListener(this); Statistics.getInstance().init(this); Statistics.getInstance().Login(19911019); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.button1: Intent intent = new Intent(this, TestUtilJar.class); startActivity(intent); break; } } }
同時在Manifest中註冊TestUtilJar 這個Activity
<activity
android:name="com.example.selfjar.TestUtilJar"
>
</activity>
</pre>
方案一是官方提供的方法應該比較好適合自己公司開發和引用開原始碼,但是有的時候是需要給第三方公司提供支援的,當然這個時候不想他們看到我們的原始碼,這時候採用方案二是比較理想的。