现在的位置: 首页 > 综合 > 正文

android模块化app开发笔记-1环境搭建 android模块化app开发笔记-1环境搭建

2017年09月28日 ⁄ 综合 ⁄ 共 5529字 ⁄ 字号 评论关闭
 

android模块化app开发笔记-1环境搭建

分类: android 773人阅读 评论(2) 收藏 举报

由于项目做的越来越大,业务上就产生了要将app模块化的需求,所谓模块化就是将一个app分成不同功能的小模块(插件),当安装程序的时候并不需要将所有模块一次全部安装,用户可以在需要的时候视情况从服务器上更新添加小插件。

   android上模块化一直都有人在摸索也出现了不少框架各有优特点,我学习apkplug这个插件化框架。这个框架的特点是

 1)插件就是普通apk文件,开发插件跟普通app没有太大区别省去了学习固定api的功夫了。

 2)插件apk不用在本地安装,网上比较经典的插件化框架都是通过android:sharedUserId="xxx"的形式将插件与app进行关联,而apkplug不用安装在app进程中运行也算是它的一大特点

 3)通过标准OSGI服务实现插件间通讯,我们开发应用时就可以定义自己的通讯接口了,而不必拘泥于固定的接口。

一 环境搭建

    从apkplug官网下载其最新的sdk解压出来的文件目录结构为如图1

新建一个主应用工程我取名为myapkplughelloworld,将armeabi,Bundle1.4.0.jar两个文件放入工程的libs文件夹中如图2

配置应用权限到工程的AndroidManifest.xml中

<!-- 插件平台需要的权限! -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 
    <uses-permission android:name="android.permission.INTERNET"/> 

另外将以下代码加入到<application></application>节点中
<!-- 插件平台需要的配置! -->
        <activity
            android:name="org.apkplug.app.apkplugActivity"  
            android:configChanges="orientation|keyboardHidden"
        />

下一步便是调用SDK启动插件了。

这里需要写一个PropertyInstance接口它是apkplug定义的目的是为了插件框架启动时传人一些启动参数,我够出来这个接口的定义如下,具体详细使用可以看apkplug官方提供的文档基本上是模块化的东西

[java] view
plain
copy

  1. public interface PropertyInstance {  
  2.     /** 
  3.      * 框架配置信息获取接口 
  4.      * 框架将通过该接口从系统获取必要信息 
  5.      * 可以通过该接口实现框架信息的本地保存 
  6.      * @param key 
  7.      * @return 
  8.      */  
  9.     public  String getProperty(String key);  
  10.     /** 
  11.      * 框架配置信息设置接口 
  12.      * 框架通过该接口设置其产生的配置信息 
  13.      * 可以通过该接口实现框架信息的本地保存 
  14.      * @param key 
  15.      * @param v 
  16.      */  
  17.     public  void setProperty(String key,String v);  
  18.     /** 
  19.      * 框架启动时将自动安装该该函数提供的文件 
  20.      * @return  本地插件绝对路径 
  21.      */  
  22.     public String[] AutoInstall();  
  23.     /** 
  24.      * 框架启动时将自动安装并启动该该函数提供的文件 
  25.      * @return  本地插件绝对路径 
  26.      */  
  27.     public String[] AutoStart();  
  28. }  

 

PropertyInstance写好以后便可以调用FrameworkInstance类启动框架了如下代码

[java] view
plain
copy

  1. try  
  2.   {  
  3.          
  4.      FrameworkInstance frame=FrameworkFactory.getInstance().start(null,Launcher.this,  
  5.       MyProperty.getInstance(this.getApplicationContext()));  
  6.    }catch (Exception ex){  
  7.       System.err.println("Could not create : " + ex);  
  8.       //ex.printStackTrace();  
  9.             StringBuffer buf=new StringBuffer();  
  10.             buf.append("插件平台启动失败:\n");  
  11.             buf.append(ex.getMessage());  
  12.             this.setTitle(buf.toString());  
  13.             Toast.makeText(this"插件平台启动失败",  
  14.                      Toast.LENGTH_SHORT).show();  
  15.    }  

如果不出意外插件框架便启动完毕了,通过启动完成后的FrameworkInstance类可以获得框架的第一个内置插件SystemBundle。这个插件很重要它是我们进入框架的一个入口,我们可以通过它调用或启动其他框架的类与activity,下面将列出调用activity的代码

二 编写插件

   首先新建一个工程myBundle将SDK包中的OSGI.jar引入到工程(注意这里osgi.jar包不能直接放入libs文件夹中,我们仅引入但不编译否则框架加载插件时会报错,因为包冲突)中如下图

 

接下来还需要写两个文件,一个是org.osgi.framework.BundleActivator接口,框架启动时将调用我们写的这一个类。另外一个是plugin.xml文档它用于配置插件的启动参数,比如启动的BundleActivator路径,启动的Activity,需要引出的包等。详细可以看官网plugin.xml配置说明http://www.apkplug.com/guide/#39 一下是我写的两个文件代码

[java] view
plain
copy

  1. public class SimpleBundle implements BundleActivator  
  2. {  
  3.     private BundleContext mcontext = null;  
  4.     public void start(BundleContext context) throws Exception  
  5.     {  
  6.         System.err.println("你号我是插件,我已经启动了 我的BundleId为:"+context.getBundle().getBundleId());  
  7.         this.mcontext = context;  
  8.     }  
  9.      
  10.     public void stop(BundleContext context)  
  11.     {  
  12.         System.err.println("你号我是插件,我被停止了 我的BundleId为:"+context.getBundle().getBundleId());  
  13.         
  14.     }  
  15.   
  16. }  
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <plugin-features    
  4.     Bundle-Name="myBundle"   
  5.     Bundle-SymbolicName="com.example.mybundle"    
  6.     Bundle-Version="1.0.0"  
  7.     date="2013.10.223"  
  8.     provider-name="插件开发商的名称"   
  9.     provider-url=""   
  10.     Bundle-Activator="com.example.mybundle.SimpleBundle"  
  11.     Bundle-Activity="com.example.mybundle.MainActivity"  
  12.     Export-Package="com.example.mybundle"     
  13.     >  
  14. </plugin-features>  

记得插件中的Activity都需要继承框架的BundleActivity。最后编译插件将得到的apk文件复制到主应用的assets文件夹中(如果要实现网络更新可以使用apkplug提供的远程插件托管服务)

下一步在主应用我们写的PropertyInstance接口的public String[] AutoStart()方法中给出框架启动是需要启动的插件文本文件路径(也就是我们刚才编译得到的插件)

[java] view
plain
copy

  1. public String[] AutoStart() {  
  2.         File f0=null;  
  3.         try {  
  4.             InputStream in=context.getAssets().open("myBundle.apk");  
  5.             f0=new File(context.getFilesDir(),"myBundle.apk");  
  6.             if(!f0.exists())  
  7.              copy(in, f0);  
  8.         } catch (IOException e) {  
  9.             // TODO Auto-generated catch block  
  10.             e.printStackTrace();  
  11.         }  
  12.           
  13.     return new String[]{"file:"+f0.getAbsolutePath()};  
  14.     }  

这样当插件启动时便会同时启动我们的插件了。

这还没有完我们还需要通过SystemBundle来启动插件的Actvitiy

启动插件的Actvitiy需要调用框架提供的一个OSGI服务

这里给出模版代码

[java] view
plain
copy

  1. /** 
  2.      * 获取系统提供的StartActivity服务来启动一个插件中的Activity 
  3.      * 前提时插件中已在plugin.xml设置了Export-Package中添加了该 
  4.      * Activity完整包路径 否则会找不到该Activity 
  5.      * @param name 
  6.      * @throws Exception 
  7.      */  
  8.     public void startActivity(String ActivityClass) throws Exception{  
  9.         System.out.println(ActivityClass);  
  10.         BundleContext mcontext=frame.getSystemBundleContext();  
  11.         ServiceReference reference=mcontext.getServiceReference(StartActivity.class.getName());  
  12.         if(null!=reference){  
  13.             StartActivity service=(StartActivity) mcontext.getService(reference);  
  14.             if(service!=null){  
  15.                 Intent i=new Intent();  
  16.                 i.setClassName(this, ActivityClass);  
  17.                 i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  18.                 service.StartActivity(mcontext, i);  
  19.             }  
  20.         mcontext.ungetService(reference);  
  21.         }  
  22.     }  

 最后运行主应用便可以看到插件apk中的界面了有图有真相

最后给出源码

 

抱歉!评论已关闭.