1. 程式人生 > >Android外掛技術——(三)載入未安裝apk

Android外掛技術——(三)載入未安裝apk

上一篇我們介紹了載入已安裝apk,本篇將介紹載入未安裝apk。

未安裝apk由於系統毫不知情,因此無法通過系統api獲取其上下文,自然也就無法獲取其資源。接下來,我們將另闢蹊徑來解決這個問題。

步驟如下:
一、採用上一篇中的Android Host工程,仍然匯出外掛介面類
二、新建Android外掛工程,匯入外掛介面類,編譯成apk,並push到手機
三、執行Android Host,載入外掛

Android Host工程如下

Android Host工程目錄

public class MainActivity extends Activity {

    private Button mBtn;

    @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtn = (Button) findViewById(R.id.btn); mBtn.setOnClickListener(new View.OnClickListener() { @Override public
void onClick(View v) { // TODO Auto-generated method stub loadPlugin(); } }); } private void loadPlugin() { File jarFile = new File(getExternalCacheDir(), "AndroidPlugin.apk"); File outputDir = getDir("plugin", 0); FileUtils.deleteDirectory(outputDir); DexClassLoader loader = new
DexClassLoader(jarFile.getAbsolutePath(), outputDir.getAbsolutePath(), null, getClass().getClassLoader()); try { Class<?> clazz = loader.loadClass("com.example.androidplugin.MainActivity"); IPlugin plugin = (IPlugin) clazz.newInstance(); String text = String.format("getInt: %d, getString: %s", plugin.getInt(), plugin.getString()); Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

Android外掛工程

Android外掛工程目錄

public class MainActivity extends Activity implements IPlugin {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public int getInt() {
        // TODO Auto-generated method stub
        return 100;
    }

    @Override
    public String getString() {
        // TODO Auto-generated method stub
        return "Hello, This is Plugin!";
    }
}

有一點需要注意:外掛工程中不能直接匯入外掛介面jar,如下

Eclipse匯入jar配置

不能選擇Add JARs,而是應該選擇Add External JARs,否則會報執行時錯誤如下

Eclipse匯入jar導致執行時錯誤

我們注意到外掛工程中外掛的介面jar放在libs_ex目錄中,而不是libs目錄中,就是為避免eclipse自動將libs中的jar直接新增到工程中了。

執行Host工程,可以成功地載入外掛apk中的MainActivity,並呼叫其外掛介面getString返回了字串,然而這裡MainActivity只是被當做了一個普通java類被調起而已,並不是真正意義上的Android元件,我們可以嘗試著在getString時返回Android字串資源。如下:

public class MainActivity extends Activity implements IPlugin {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public int getInt() {
        // TODO Auto-generated method stub
        return 100;
    }

    @Override
    public String getString() {
        // TODO Auto-generated method stub
        return getString(R.string.hello_world);
    }
}

執行Host調起外掛,結果會崩潰,日誌如下:

這裡寫圖片描述

可見外掛中的Activity只是一個普通的Java類,無法獲取其系統資源,要獲取系統資源必須獲取外掛的Resources,Host中修改如下:

public class MainActivity extends Activity {

    private Button mBtn;

    private Resources mPluginResources;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBtn = (Button) findViewById(R.id.btn);
        mBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                loadPlugin();
            }
        });

    }

    private void loadPlugin() {
        File jarFile = new File(getExternalCacheDir(), "AndroidPlugin.apk");
        File outputDir = getDir("plugin", 0);

        FileUtils.deleteDirectory(outputDir);

        DexClassLoader loader = new DexClassLoader(jarFile.getAbsolutePath(),
                outputDir.getAbsolutePath(), null, getClass().getClassLoader());

        try {
            Class<?> clazz = loader.loadClass("com.example.androidplugin.MainActivity");
            IPlugin plugin = (IPlugin) clazz.newInstance();

            loadResources(jarFile.getAbsolutePath());

            int resId = mPluginResources.getIdentifier("hello_world", "string",
                    "com.example.androidplugin");
            String text = mPluginResources.getString(resId);

            Toast.makeText(this, plugin.getInt() + text, Toast.LENGTH_SHORT).show();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void loadResources(String dexPath) {
        AssetManager assetManager = null;

        try {
            assetManager = AssetManager.class.newInstance();
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, dexPath);
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        Resources resources = getResources();
        mPluginResources = new Resources(assetManager, resources.getDisplayMetrics(),
                resources.getConfiguration());
        mPluginResources.newTheme().setTo(getTheme());
    }
}

相關推薦

Android外掛技術——載入安裝apk

上一篇我們介紹了載入已安裝apk,本篇將介紹載入未安裝apk。 未安裝apk由於系統毫不知情,因此無法通過系統api獲取其上下文,自然也就無法獲取其資源。接下來,我們將另闢蹊徑來解決這個問題。 步驟如下: 一、採用上一篇中的Android Host工程,仍

Android熱補丁動態修復技術—— 使用Javassist注入位元組碼,完成熱補丁框架雛形可使用

一、關於CSDN mardown編輯器的坑 Android熱補丁動態修復技術(三)這篇博文其實在4月8日的晚上已經發布了,然後緊接著寫第四篇,但是我將(四)儲存到草稿箱時,發現已經發布的(三)消失了,取而代之的是第四篇博文。 在論壇問過版主,可能是因為我誤操

從零開始學習音視頻編程技術 開發環境搭建Qt4.86手動設置環境,主要就是設置g++和qmake,比較透徹,附下載鏈接

路徑 details 分享 baidu 末尾 是我 其中 找到 source 1.先下載安裝Qt 我們使用的版本是4.8。 可以自行百度下載也可以從下面的網盤地址下載: Qt庫和編譯器下載: 鏈接:http://pan.baidu.com/s/1hrUxLIG 密碼

中小型網絡最全的VLAN技術——實現不同網段間通信——層交換路由原理

三層交換 VLAN間通實現不同網段間通信 實驗概況: 如上兩圖所示,多vlan間通信建立在三層交換的基礎上,通過給虛擬vlan配置Ip網關,從而實現路由功能,實現不同VLAN間通信。如若跨多個VLAN或者路由器,則配置相應的靜態路由。原理解釋: 路由器的工作原理: 1.僅僅查看數據包中的IP地址中的目

Android Camera2 拍照——切換攝像頭,延時拍攝和閃光模式

openca any The visible surface else 提示 再次 .cn 原文:Android Camera2 拍照(三)——切換攝像頭,延時拍攝和閃光模式

Android Studio 學習 廣播

else set local activity .... order ... void test 動態註冊監聽網絡變化 創建intentFilter 並addAction 代表了監聽哪個廣播 然後使用registerReceiver()方法 將intentFilter 與

Android 開發:安卓常用控制元件以及仿《微門戶》登入介面實現

一、常用控制元件: 1、文字類控制元件 TextView 負責展示文字,非編輯 EditText 可編輯文字控制元件 2、按鈕類控制元件 Button 按鈕 ImageButton 圖片按鈕 RadioButton與RadioGroup 單

谷歌三大核心技術Google BigTable中文版

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Docker核心技術

Docker核心技術 Docker容器資料卷 Docker容器資料卷是什麼? Docker容器資料卷能幹嘛? Docker容器資料卷的實操 直接命令新增 DockerFile新增 資料卷容器

Android進階:Application啟動過程(最詳細&最簡單)

1.前言 最近一直在看 《Android進階解密》 的一本書,這本書編寫邏輯、流程都非常好,而且很容易看懂,非常推薦大家去看看(沒有收廣告費,單純覺得作者寫的很好)。 上一篇簡單的介紹了Android進階(二): 應用程序啟動過程,最終知道了ActivityThrea

PDF技術-Java實現圖片轉PDF檔案

圖片轉pdf檔案同樣採用itext,將圖片加入即可 1)使用IText轉換 原理: 使用IText建立pdf,新增圖片。 優點: 速度快。 具體實現 public class Image2PDF { /*** @param picturePath 圖片地址*/

Android入門筆記

三、RecyclerView、ViewHolder 和 Adapter      3.1 功能概括 RecyclerView :任務僅限於回收和定位螢幕上的 View,且其自身不會建立檢視,它建立的只是 ViewHolder。 ViewHolder:容納 View

Android開發筆記螢幕解析度

在app編碼中經常需要獲取手機的螢幕解析度(寬*高),原來我直接上網拷貝程式碼,但在使用過程中卻發現諸多不便。 不便一:下面程式碼中的getWidth和getHeight在adt上提示deprecated已經廢棄了,實在扎眼 WindowManager wm = get

egret 釋出android原生專案JS與原生通訊

JS與Java通訊 JS向Java傳送訊息 Java註冊接收訊息的方法: nativeAndroid.setExternalInterface("sendToNative", new INativePlayer.INativeInterface() {  &n

Android輸入系統InputReader的加工型別和InputDispatcher的分發過程

關聯絡列 解析WMS系列 深入理解JNI系列 輸入系統系列 前言 在上一篇文章中,我們學習了輸入事件的處理,輸入事件會交由InputDispatcher進行分發,那麼InputDispatcher是如何進行分發的?這篇文章會給你答案。 1.InputReader的加工型別 在Android輸入系統(二

Android Firebase接入--Firebase 崩潰日誌報告Crashlytics

Firebase崩潰日誌報告可以自動記錄應用內崩潰資訊,只需簡單的幾步,就可以將Firebase Crashlytics新增到安卓工程中,然後Firebase Crashlytics就會自動的收集應用內崩潰資訊,包括錯誤型別,程式碼定位等等,非常的方便實用。 一、配置A

OpenGL 載入貼圖

有了模型還需要貼圖。 載入貼圖 的流程大體分為兩部分,首先是圖片的解碼,其次是使用UV座標與模型對應。本文主要從底層原理和第三方庫兩個方面來介紹 載入貼圖 。解碼下面分別介紹硬編碼實現和SOIL庫兩種方式。硬編碼實現因為載入不同的型別圖片偏移值不一樣,載入圖片之前要確定圖片型

Android-json解析:原生JSONObject+JSONArray的解析、遍歷及生成等

一、JSONObject和JSONArray的資料表示形式 JSONObject的資料是用 { } 來表示的, 例如: { "id":"1", "courseID":"化學", "title":"滴定實驗",

一步一步開發Game伺服器載入指令碼和伺服器熱更新

大家可能對遊戲伺服器的執行不太理解或者說不太清楚一些機制。 但是大家一定會明白一點,當程式在執行的時候出現一些bug,必須及時更新,但是不能重啟程式的情況下。 這裡牽涉到一個問題。比如說在遊戲裡面,,如果一旦開服,錯非完全致命性bug,否則是不能頻繁重啟伺服器程式的, 你重啟一次就可能流失一部分玩家。那

一步一步開發Game伺服器載入指令碼和伺服器熱更新完整版

可是在使用過程中,也許有很多會發現,動態載入dll其實不方便,應為需要預先編譯程式碼為dll檔案。便利性不是很高。 那麼有麼有辦法能做到動態實時更新呢???? 官方提供了這兩個物件,動態編譯原始檔。 提供對 C# 程式碼生成器和程式碼編譯器的例項的訪問。 CSharpCodeProvider