美文网首页
android-VirtualAPK插件框架鼓捣实践

android-VirtualAPK插件框架鼓捣实践

作者: 小钟钟同学 | 来源:发表于2018-12-11 15:59 被阅读51次

系统重装后,环境丢失了,需要重新安装下。

环境安装

1:java安装
2:android studio 安装

android studio 安装问题小计

解决方式:
1:安装下载SDK背墙问题,


image.png

在此文件配置后面添加禁用自动检测SDK

disable.android.first.run=true

2:在欢迎界面,点击Config---》seting--->设置HTTP代理


image.png image.png image.png

PS:
Android SDK 在线更新镜像服务器资源:

大连东软信息学院镜像服务器地址:

http://mirrors.neusoft.edu.cn 端口:80
北京化工大学镜像服务器地址:

IPv4: http://ubuntu.buct.edu.cn/ 端口:80
IPv4: http://ubuntu.buct.cn/ 端口:80
IPv6: http://ubuntu.buct6.edu.cn/ 端口:80
上海GDG镜像服务器地址:

http://sdk.gdgshanghai.com 端口:8000
中国科学院开源协会镜像站地址:

IPV4/IPV6: http://mirrors.opencas.cn 端口:80
IPV4/IPV6: http://mirrors.opencas.org 端口:80
IPV4/IPV6: http://mirrors.opencas.ac.cn 端口:80
腾讯Bugly 镜像:

http://android-mirror.bugly.qq.com 端口:8080
腾讯镜像使用方法: http://android-mirror.bugly.qq.com:8080/include/usage.html

测试发现只有腾讯的可用!

不过最后折腾了下还是发现,使用代理的方式到最后还是有问题。

直接离线的安装SDK(注意要你的网络好一点,不然你也会等半天)

下载地址:
http://tools.android-studio.org/index.php/sdk

image.png

指定下载的安装路径!

测试-android studio 是否能使用

image.png

随意的新建一个项目,进行安装启动测试。

====================
插件化鼓捣步骤:

1: 编写宿主应用

1)新建项目


image.png
image.png
image.png image.png image.png

等待项目构建:


image.png

2)宿主构建文件的配置信息

image.png

修改为:3.0.0,并添加

classpath 'com.didi.virtualapk:gradle:0.9.8.4'
image.png

重新的编译一下:

image.png

错误,直接点击安装


image.png

3)模块配置文件修改,引入

image.png
apply plugin: 'com.didi.virtualapk.host'

image.png
dependencies {
    compile 'com.didi.virtualapk:core:0.9.6'
}
image.png

再次重新编译一下:


image.png

PS:提示更新版本的话,不要更新哟

image.png

添加混淆规则:


image.png
-keep class com.didi.virtualapk.internal.VAInstrumentation { *; }
-keep class com.didi.virtualapk.internal.PluginContentResolver { *; }
-dontwarn com.didi.virtualapk.**
-dontwarn android.content.pm.**
-keep class android.** { *; }

4)在宿主项目里新建一个类继承于 Application,用于应用其的时候就初始化插件。

image.png

重载该方法:

image.png

初始化插件:


image.png
package com.game.zyx.pluginapp;

import android.app.Application;
import android.content.Context;

//导入插件包
import com.didi.virtualapk.PluginManager;

public class PluginApp extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // 插件初始化
        PluginManager.getInstance(base).init();
    }
}

5)宿主项目配置允许访问文件权限,用户加载外部APK

image.png

6)修改入口MainActivity文件

package com.game.zyx.pluginapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.didi.virtualapk.PluginManager;

import java.io.File;

import static android.os.Environment.getExternalStorageDirectory;

public class MainActivity extends AppCompatActivity {

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

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                apkLoad();
            }
        });

        findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

    }

    //   导入APK
    public void apkLoad() {
        Toast.makeText(MainActivity.this, "加载外部APK-开始", Toast.LENGTH_SHORT).show();
        // 加载plugin.apk插件包
        PluginManager pluginManager = PluginManager.getInstance(this);
        File apk = new File(getExternalStorageDirectory(), "plugin.apk");
        if (apk.exists()) {
            try {
                pluginManager.loadPlugin(apk);
                Toast.makeText(MainActivity.this, "加载外部APK-完成", Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                Toast.makeText(MainActivity.this, "加载外部APK-异常", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        } else {
            Toast.makeText(MainActivity.this, "APK文件不存在", Toast.LENGTH_SHORT).show();
        }
    }
}

2 编写插件APK项目:

PS需要注意事项点:
1:所有的插件的包名不可以和主包名同包。
2:所有的插件的包资源名称也不可以和主包同名。

1)新建项目


image.png

修改配置:

apply plugin: 'com.didi.virtualapk.plugin'

// 插件配置信息,放在文件最下面
virtualApk {
    packageId = 0x6f             // 插件资源id,避免资源id冲突
    targetHost='/PluginApp/app'     // 宿主工程的路径
    applyHostMapping = true      // 插件编译时是否启用应用宿主的apply mapping
}

注意宿主目录为:


image.png

2)重新编译更新

3)进行插件打包


image.png

4)提取插件包

tiq

5)把APK存放在SD卡的根目录下(一般网上下载话,自定定义加载目录),用于读取加载

上传文件到根目录下面

adb push D:\PluaginChajian\app\build\outputs\apk\release\plugin.apk /sdcard/plugin.apk
image.png

3:修改宿主文件入口

image.png
package com.game.zyx.pluginapp;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.didi.virtualapk.PluginManager;

import java.io.File;

import static android.os.Environment.getExternalStorageDirectory;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                apkLoad();
            }
        });

        findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

    }

    //   导入APK
    public void apkLoad() {
        Toast.makeText(MainActivity.this, "加载外部APK-开始", Toast.LENGTH_SHORT).show();
        // 加载plugin.apk插件包
        PluginManager pluginManager = PluginManager.getInstance(this);
        File apk = new File(getExternalStorageDirectory(), "plugin.apk");
        if (apk.exists()) {
            try {
                pluginManager.loadPlugin(apk);
                Toast.makeText(MainActivity.this, "加载外部APK-完成", Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                Toast.makeText(MainActivity.this, "加载外部APK-异常", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        } else {
            Toast.makeText(MainActivity.this, "APK文件不存在", Toast.LENGTH_SHORT).show();
        }
    }

    //    启动插件
    public void actionPluainChild() {
        Intent intent = new Intent();
        // 插件件的报名 和 插件启动的入口Actinity
        intent.setClassName("com.game.childzyx.pluaginchajian", "com.game.childzyx.pluaginchajian.ChildActivity");
        startActivity(intent);

    }


}

启动测试报错

android.content.pm.PackageParser$PackageParserException: Failed adding asset path: /storage/emulated/0/plugin.apk

无法加载APK!!!

仔细核对加载的APK,发现好像不是pluagin下的APK包:

gchuab
D:\PluaginChajian\app\build\outputs\plugin\release\plugin.apk

重新上传:

adb push D:\PluaginChajian\app\build\outputs\plugin\release\plugin.apk /sdcard/plugin.apk

测试还是失败!!!!!!

=======================
后来想了一下 版本问题,6.0以上关于权限读写的问题!!!
修改了一下!!!增加权限申请!!!

package com.game.zyx.pluginapp;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.didi.virtualapk.PluginManager;

import java.io.File;

import static android.os.Environment.getExternalStorageDirectory;

public class MainActivity extends AppCompatActivity {

    //读写权限
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};
    //请求状态码
    private static int REQUEST_PERMISSION_CODE = 1;

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


        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
            }
        }


//
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                apkLoad();
            }
        });

        findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                actionPluainChild();
            }
        });

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CODE) {
            for (int i = 0; i < permissions.length; i++) {
                Log.i("MainActivity", "申请的权限为:" + permissions[i] + ",申请结果:" + grantResults[i]);
            }
        }
    }

        //   导入APK
        public void apkLoad () {
            Toast.makeText(MainActivity.this, "加载外部APK-开始", Toast.LENGTH_SHORT).show();
            // 加载plugin.apk插件包
            PluginManager pluginManager = PluginManager.getInstance(this);
            File apk = new File(android.os.Environment.getExternalStorageDirectory(), "plugin.apk");
            if (apk.exists()) {
                try {
                    pluginManager.loadPlugin(apk);
                    Toast.makeText(MainActivity.this, "加载外部APK-完成", Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    Toast.makeText(MainActivity.this, "加载外部APK-异常", Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
                }
            } else {
                Toast.makeText(MainActivity.this, "APK文件不存在", Toast.LENGTH_SHORT).show();
            }
        }

        //    启动插件
        public void actionPluainChild () {

            if (PluginManager.getInstance(this).getLoadedPlugin("com.game.childzyx.pluaginchajian") == null) {
                Toast.makeText(this, "plugin not loaded", Toast.LENGTH_LONG).show();
                return;
            }
            Intent intent = new Intent();
            // 插件件的报名 和 插件启动的入口Actinity
            intent.setClassName("com.game.childzyx.pluaginchajian", "com.game.childzyx.pluaginchajian.ChildActivity");
            startActivity(intent);

        }


    }

点击运行:

最终测试完成!!!了 !!!可以加载!!!

=============
2018-12-12 10:42:16
==================

打包遇到的问题点

问题1:打签名包的时候总是提示说包有损坏。

image.png

问题2:使用命令打包提示也失败

D:\PluginApp>gradlew clean assemblePlugin

具体打包提示:

D:\PluginApp>gradlew clean assemblePlugin
Starting a Gradle Daemon, 2 incompatible Daemons could not be reused, use --status for details

> Configure project :app 
Configuration 'compile' in project ':app' is deprecated. Use 'implementation' instead.
Observed package id 'build-tools;28.0.0-rc2' in inconsistent location 'F:\android-sdk\build-tools\28.0.0-preview' (Expected 'F:\android-sdk\build-tools\28.0.0-rc2')
Observed package id 'build-tools;28.0.0-rc2' in inconsistent location 'F:\android-sdk\build-tools\28.0.0-preview' (Expected 'F:\android-sdk\build-tools\28.0.0-rc2')


FAILURE: Build failed with an exception.

* What went wrong:
Task 'assemblePlugin' not found in root project 'PluginApp'.

* Try:
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
See https://docs.gradle.org/4.6/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 16s

D:\PluginApp>

问题3:使用Build-->build apks也还是提示包损坏

b

问题4:使用Gradle打包也还是提示损坏

image.png

最终解决:

最终直接使用ADB上传的方式进行安装:没问题!!!

相关文章

网友评论

      本文标题:android-VirtualAPK插件框架鼓捣实践

      本文链接:https://www.haomeiwen.com/subject/ytsdhqtx.html