Android動態加載so文件


在Android中調用動態庫文件(*.so)都是通過jni的方式,而且往往在apk或jar包中調用so文件時,都要將對應so文件打包進apk或jar包,工程目錄下圖:

image

以上方式的存在的問題:

1、缺少靈活性比較類似靜態加載了(不是靜態加載),能加載的so文件綁定死了;

2、但so文件很多或很大時,會導致對應的apk和jar包很大;

3、不能動態的對so文件更新;

 

Android中加載so文件的提供的API:

void System.load(String pathName);

說明:

1、pathName:文件名+文件路勁;

2、該方法調用成功后so文件中的導出函數都將插入的系統提供的一個映射表(類型Map);

 

看到以上對System.load(String pathName);的函數說明可定有人會想到將so文件放到一個指定的目錄然后再通過參數pathName直接引用該目錄的路勁和對應的so文件問題不就解決了嗎?

這里有個問題被忽略了,那就是System.load只能加載兩個目錄路勁下的so文件:

1、/system/lib ;

2、安裝包的路勁,即:/data/data/<packagename>/…

而且這兩個路勁又是有權限保護的不能直接訪問;

 

問題解決方法:

先從網絡下載so文件到手機目錄(如:/test/device/test.so) –> 將test.so加載到內存(ByteArrayOutputStream) –> 然后保存到對用安裝包目錄;

具體代碼如下:

try {
            String localPath = Environment.getExternalStorageDirectory() + path;
            Log.v(TAG, "LazyBandingLib localPath:" + localPath);

            String[] tokens = mPatterns.split(path);
            if (null == tokens || tokens.length <= 0
                    || tokens[tokens.length - 1] == "") {
                Log.v(TAG, "非法的文件路徑!");
                return -3;
            }
            // 開辟一個輸入流
            File inFile = new File(localPath);
            // 判斷需加載的文件是否存在
            if (!inFile.exists()) {
                // 下載遠程驅動文件
                Log.v(TAG, inFile.getAbsolutePath() + " is not fond!");
                return 1;
            }
            FileInputStream fis = new FileInputStream(inFile);

            File dir = context.getDir("libs", Context.MODE_PRIVATE);
            // 獲取驅動文件輸出流
            File soFile = new File(dir, tokens[tokens.length - 1]);
            if (!soFile.exists()) {
                Log.v(TAG, "### " + soFile.getAbsolutePath() + " is not exists");
                FileOutputStream fos = new FileOutputStream(soFile);
                Log.v(TAG, "FileOutputStream:" + fos.toString() + ",tokens:"
                        + tokens[tokens.length - 1]);

                // 字節數組輸出流,寫入到內存中(ram)
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = -1;
                while ((len = fis.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                // 從內存到寫入到具體文件
                fos.write(baos.toByteArray());
                // 關閉文件流
                baos.close();
                fos.close();
            }
            fis.close();
            Log.v(TAG, "### System.load start");
            // 加載外設驅動
            System.load(soFile.getAbsolutePath());
            Log.v(TAG, "### System.load End");

            return 0;

        } catch (Exception e) {
            Log.v(TAG, "Exception   " + e.getMessage());
            e.printStackTrace();
            return -1;

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM