Android動態加載so文件


轉自:http://www.shaoqun.com/a/105310.aspx

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

以上方式的存在的問題:

  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