andriod 原始碼開發,打包so到apk

jackie_gnu發表於2011-07-20
 命令方式將so檔案打包進apk
        使用android SDK原始碼 開發APK,將so檔案打包進apk,這樣可以只提供給客戶一個apk.
1.        含義全程式碼的so打包.
a)        建立工程,並使用本地呼叫,java檔案如下
package test.jni;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class jnitest extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView  tv = new TextView(this);
        int       x  = 55;
        int       y  = 8;
        System.loadLibrary("apptest");
        //System.loadLibrary("testapi");
        int  z = appadd(x, y);
        tv.setText( x + "+" + y + "=" + z );
        setContentView(tv);
    }
    public native int appadd(int  x, int  y);
}
b)        在工程的根目錄建立Android.mk,內容如下.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user eng
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := jnitest
LOCAL_JNI_SHARED_LIBRARIES := libapptest
include $(BUILD_PACKAGE)
include $(LOCAL_PATH)/jni/Android.mk
# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
其中LOCAL_MODULE_TAGS名字要和目標系統一致,否則編譯產生的apk檔案不能安裝到目標系統,.
LOCAL_JNI_SHARED_LIBRARIES := libapptest 把我們另外編譯成的so檔案放到apk檔案裡的libs/armeabi裡
include $(LOCAL_PATH)/jni/Android.mk為了編譯本地檔案成為so
c)        在工程根目錄建立jni資料夾,在jni檔案裡建立Android.mk和callapp.c,他們內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user eng
LOCAL_MODULE    := libapptest
LOCAL_SRC_FILES := callapp.c
LOCAL_C_INCLUDES += \
        $(JNI_H_INCLUDE)
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE_TAGS :要和工程的一致,否則編譯不通過
LOCAL_C_INCLUDES += \
        $(JNI_H_INCLUDE)  為了讓jni編譯通過,因為工程通過jni呼叫本地庫
#include <jni.h>
JNIEXPORT jint JNICALL Java_test_jni_jnitest_appadd
  (JNIEnv *env, jobject obj, jint x, jint y){
    return x +y;
}
d)        把工程檔案放到SDK platform\packages\apps目錄下,然後進入該目錄,命令裡輸入mm,進行該工程的編譯.(之前要再platform之前把工程目標設定好)
e)        編譯出來的apk 在platform/out/target/product/sk886x/system/app裡可以找到,其中sk886x 是目標平臺. 開啟該apk檔案,可以看到libapptest.so存在在包裡的libs/armeabi資料夾裡. 執行該apk,可以正常執行,顯示正確答案.
2.        本地庫so檔案里加列印訊息.
a)        這樣修改jni資料夾下Android.mk.新增
LOCAL_SHARED_LIBRARIES := libutils
b)        Callapp.c如下
#include <jni.h>
#define LOG_TAG "TestThunderLib"
#undef LOG
#include <utils/Log.h>
JNIEXPORT jint JNICALL Java_test_jni_jnitest_appadd
  (JNIEnv *env, jobject obj, jint x, jint y){
          LOGD("TEST %d+%d=%d",x,y,x+y);
    return x+y;//add22(x,y);
}
c)        重新再工程根目錄輸入mm,編譯得到apk,執行到目標機,通過uart 敲入命令 logcat,會發現有 log 輸出 TEST 55 + 66 = 121 等正確資訊
3.        在以上的基礎上,我引進另外的庫檔案,給callapp.c呼叫.
a)        此庫我們用NDK 編譯出來,請保證和目標平臺版本一致.檔案如下:
i.        Add.c
#include "add.h"
int  add22(int  x, int  y){
    return x + y;
}
ii.        Add.h
#ifndef ADD_H
#define ADD_H

extern int add22(int  x, int  y);

#endif /* ADD_H */
iii.        NDK 的Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := testapi
LOCAL_SRC_FILES := add.c
LOCAL_PRELINK_MODULE := false
include $(BUILD_STATIC_LIBRARY)
#include $(BUILD_SHARED_LIBRARY)
b)        選擇不同的built方式,經NDK 編譯,可以得到libtestapi.a,libtestapi.so
c)        此時,工程目錄下jni資料夾裡Android.mk裡新增
LOCAL_STATIC_LIBRARIES := libtestapi
表示吧libtestapi作為靜態庫編譯到libapptest.so裡.
d)        Callapp.c 內容如下
#include <jni.h>
#include "add.h"
#define LOG_TAG "TestThunderLib"
#undef LOG
#include <utils/Log.h>
JNIEXPORT jint JNICALL Java_test_jni_jnitest_appadd
  (JNIEnv *env, jobject obj, jint x, jint y){
          LOGD("TEST %d+%d=%d",x,y,x+y);
    return add22(x,y);
}
e)        在工程根目錄下輸入mm,編譯提示out/target/product/sk886x/obj/STATIC_LIBRARIES/libtestapi_intermediates/libtestapi.a 找不到,這時候我們把b)得到的libtestapi.a放到提示的資料夾裡,再重新編譯就通過.得到的apk,安裝到目標機,執行,成功.
4.        在步驟3的基礎上,我們讓callapp.c呼叫libtesapi.so
a)        修改工程根目錄,android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user eng
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := jnitest
LOCAL_JNI_SHARED_LIBRARIES := libapptest libtestapi
include $(BUILD_PACKAGE)
include $(LOCAL_PATH)/jni/Android.mk
# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))注意libapptest libtestapi 要同一行,否則,前面一個不會打包到apk裡.
b)        Jni目錄下Android.mk 裡新增
        LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user eng
LOCAL_MODULE    := libapptest
LOCAL_SRC_FILES := callapp.c
LOCAL_C_INCLUDES += \
        $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := libutils libtestapi
#LOCAL_STATIC_LIBRARIES := libtestapi
LOCAL_LDLIBS := -ldl -llog
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)               
c)        編譯,提示找不到libtestapi.so,我們把他分別複製到out/target/product/sk886x/obj/lib/和/out/target/product/sk886x/system/lib/ 這樣能編譯通過.
d)        執行apk,發現提示錯誤.由於libtestapi.so 是我們以動態共享庫提供給libapptest.so,所以libtestapi.so要放到/system/lib裡,通過adb push 到/system/lib以後,重新執行apk,可以正確執行.

相關文章