🖥️
Log4think
  • Introduction
  • Archive
  • 2016-12-13 JavaScript 中几种不同的基于 prototype 继承方式的区别
  • 2014-09-02 Facebook的Dalvik运行期补丁
  • 2014-08-19 理解AnguarJS中的模板编译
  • 2014-08-13 在Android中使用OSGi框架(Knopflerfish)
  • 2014-08-13 在Android中使用OSGi框架(Apache Felix)
  • 2014-07-30 3rd-party apt-key list for Ubuntu
  • 2014-07-21 'Failed to clone a large git repository: The remote end hung up unexpectedly'
  • 2014-07-02 genymotion Qt error in Ubuntu
  • 2014-04-30 可自动安装依赖的Ubuntu离线包安装工具 gdebi
  • 2014-04-23 解决搜狗输入法Ubuntu 14.04下黑块状态条
  • 2014-04-08 Setup Ghost blog system on Ubuntu
  • 2014-03-28 Trace a process
  • 2014-03-25 Forecast::IO 599 Internal Exception
  • 2014-03-23 Mac Tips
  • 2014-01-17 LD_LIBRARY_PATH shouldn't contain the current directory
  • 2014-01-10 Python on vim
  • 2013-11-12 ibus-pinyin doesn't work in KUbuntu 13.10
  • 2013-11-11 phpMyAdmin login error to remote server
  • 2013-11-04 Get SNMP(v3) working on Ubuntu 12.04
  • 2013-10-30 Accessing Facebook by LWP
  • 2013-10-17 Log4perl多个Appender重复输出日志的问题解决办法
  • 2013-04-19 How to enable ORMLite internal log on Android
  • 2013-02-20 Bash Shortcuts
  • 2013-02-20 '"adb shell dumpsys" parameter list'
  • 2013-01-27 循环有序数组的二分查找
  • 2013-01-23 为Java运行环境导入根证书解决Eclipse的TFS插件的"PKIX path building failed"错误
  • 2013-01-21 ant 中通过重新定义 project.all.jars.path 在 classpath 中引入外部 jar 文件
  • 2012-09-22 Android的滚动条实现细节
  • 2012-02-05 hostname自动变成bogon的问题
  • 2011-07-09 代码段速记 gist.github.com
  • 2011-07-08 A perl Data.Dumper clone for Python
  • 2011-06-22 魔兽世界私服Trinity,从源码开始
  • 2011-06-13 魔兽世界3.3.5 13930登录数据包分析
  • 2011-06-13 魔兽世界 3.3.5 13930 Trinity 认证补丁
  • 2011-05-20 统一业务模型(UBM) in ERP5
  • 2011-03-08 制作ASCII字符动画
  • 2011-01-14 Ubuntu升级导致的udevd错误修复
  • 2011-01-09 行列有序矩阵求第K个数
  • 2011-01-09 字节按位逆序
  • 2011-01-01 编程之美 1.2 中国相帅问题的一个简洁解法
  • 2010-11-26 为Windows 7/Windows Server 2008添加IPX协议
  • 2010-11-12 How to debug with Android Logging
  • 2010-09-16 利用google-code-prettify做网页内源码的语法高亮
  • 2010-09-05 10 Ways We Hurt Our Romantic Relationships
  • 2010-08-30 利用ipkall+xlite+iptel.org开通google voice
  • 2010-08-27 避免Android开发中的ANR
  • 2010-08-27 在Eclipse中查看Android SDK的源代码
  • 2010-08-18 Git中判断一个commit是否在某个branch中
  • 2010-08-04 修正auto-excerpt产生带格式的摘要
  • 2010-03-31 Go 编程语言入门教程
  • 2010-03-13 利用外部VPS主机通过ssh隧道穿透防火墙连接内网
  • 2009-12-30 旋转矩阵
  • 2009-02-10 为什么cpio要比tar好
  • 2008-12-11 ThoughtWorks 的一道笔试题
  • 2008-11-18 长距离打车如何省钱?
  • 2007-02-08 ftp后台自动上传下载
  • 2006-06-12 vi cheatsheet
  • 2006-04-19 修正mysqlcc在MySQL 5.0上常报的 Table 'xxx' doesn't exist 错误
  • 2006-04-01 'Perl中不寻常的 ?: 运算符'
  • 2005-09-13 关于IoC、低耦合、配置文件及其本质意义的思考
  • 2005-09-13 Perl与数据库DBI快速入门
  • 2005-09-12 Perl无废话入门指南
  • 2005-07-16 Solaris 下安装Perl的DBD-mysql模块失败的原因以及解决办法
  • 2004-10-15 SharpDevelop的AddInTree View 插件
  • 2004-10-14 SharpDevelop源码分析 (完整版)
由 GitBook 提供支持
在本页
  • 嵌入Framework
  • Bundle文件dex化
  • 安装、启动Bundles
  • 问题

这有帮助吗?

2014-08-13 在Android中使用OSGi框架(Knopflerfish)

上一页2014-08-19 理解AnguarJS中的模板编译下一页2014-08-13 在Android中使用OSGi框架(Apache Felix)

最后更新于5年前

这有帮助吗?

OSGi是用Java实现的一个模块化服务平台。每个模块被称之为Bundle,可以提供服务,也可以在不重启OSGi框架的情况下被安装或卸载。Knopflerfish是一个完全开源的OSGi R4.2标准的实现。

Android能够无缝的集成现有的Java代码,尽管使用的是与现有java字节码格式不兼容的虚拟机Dalvik,但是它可以轻松的将现有的jar文件和类转换为Android使用的Dalvik字节码格式。由于OSGi框架自身和Bundle都只是普通的jar文件,所以他们都应该可以在Android上运行。事实上,大多数时候是没问题的。

注意:这里只是如何在Android中嵌入OSGi系列文章的第一部分

如果只是想让OSGi框架在Android上跑起来,那么只需要编译Knopflerfish的Android版本,复制到设备上,然后就可以通过命令行启动起来了(见和)。

现在来看看如何将Knopflerfish和一系列Bundle嵌入到Android应用中,并且从应用中启动和管理OSGi框架和Bundle。

通过代码启动OSGi大概需要下面这几个步骤:

  1. 创建framework实例(通过framework factory)

  2. 初始化framework

  3. 设置initlevel,并启动/安装 bunldes

  4. 为所有的initlevel重复前述步骤

  5. 设置startlevel

  6. 启动framework

嵌入Framework

现在创建一个Android应用,包含一个Actviity。然后在app中引入framework.jar,这样就可以通过一个FrameworkFactory创建OSGi的framework实例了。

import org.knopflerfish.framework.FrameworkFactoryImpl;
import org.osgi.framework.BundleException;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
...
private Framework mFramework;
...
Dictionary fwprops = new Hashtable();
// add any framework properties to fwprops
FrameworkFactory ff = new FrameworkFactoryImpl();
mFramework = ff.newFramework(fwprops);
try {
    mFramework.init();
} catch (BundleException be) {
    // framework initialization failed
}

引入的jar文件不需要dex化,后面build的时候会自动完成这一步的。

Bundle文件dex化

现在bundle的jar文件可以被添加到应用中了,可以作为raw资源放在res/raw下面,也可以放在assets/bunldes。后面这种方式有一个优势:不需要被重命名,而且res资源的名字数量是有限的。

Bundle的jar文件需要被转换成dex格式,下面这个简单的脚本可以完成这件事:

dexify() {
    for f in $*; do
        tmpdir="`mktemp -d`"
        tmpfile="${tmpdir}/classes.dex"
        dx --dex --output=${tmpfile} ${f}
        aapt add ${f} ${tmpfile}
        rm -f ${tmpfile}
        rmdir ${tmpdir}
    done
}

安装、启动Bundles

下面这段代码可以帮助启动bundle,并设置initlevel/startlevel。

private void startBundle(String bundle) {
    Log.d(TAG, "starting bundle " + bundle);
    InputStream bs;
    try {
        bs = getAssets().open("bundles/" + bundle);
    } catch (IOException e) {
        Log.e(TAG, e.toString());
        return;
    }

    long bid = -1;
    Bundle[] bl = mFramework.getBundleContext().getBundles();
    for (int i = 0; bl != null && i < bl.length; i++) {
        if (bundle.equals(bl[i].getLocation())) {
            bid = bl[i].getBundleId();
        }
    }

    Bundle b = mFramework.getBundleContext().getBundle(bid);
    if (b == null) {
        Log.e(TAG, "can't start bundle " + bundle);
        return;
    }

    try {
        b.start(Bundle.START_ACTIVATION_POLICY);
        Log.d(TAG, "bundle " + b.getSymbolicName() + "/" + b.getBundleId() + "/"
                + b + " started");
    } catch (BundleException be) {
        Log.e(TAG, be.toString());
    }

    try {
        bs.close();
    } catch (IOException e) {
        Log.e(TAG, e.toString());
    }
}

private void installBundle(String bundle) {
    Log.d(TAG, "installing bundle " + bundle);
    InputStream bs;
    try {
        bs = getAssets().open("bundles/" + bundle);
    } catch (IOException e) {
        Log.e(TAG, e.toString());
        return;
    }

    try {
        mFramework.getBundleContext().installBundle(bundle, bs);
        Log.d(TAG, "bundle " + bundle + " installed");
    } catch (BundleException be) {
        Log.e(TAG, be.toString());
    }

    try {
        bs.close();
    } catch (IOException e) {
        Log.e(TAG, e.toString());
    }
}

private void setStartLevel(int startLevel) {
    ServiceReference sr = mFramework.getBundleContext()
        .getServiceReference(StartLevel.class.getName());
    if (sr != null) {
        StartLevel ss =
            (StartLevel)mFramework.getBundleContext().getService(sr);
        ss.setStartLevel(startLevel);
        mFramework.getBundleContext().ungetService(sr);
    } else {
        Log.e(TAG, "No start level service " + startLevel);
    }
}

private void setInitlevel(int level) {
    ServiceReference sr = mFramework.getBundleContext()
        .getServiceReference(StartLevel.class.getName());
    if (sr != null) {
        StartLevel ss =
            (StartLevel)mFramework.getBundleContext().getService(sr);
        ss.setInitialBundleStartLevel(level);
        mFramework.getBundleContext().ungetService(sr);
        Log.d(TAG, "initlevel " + level + " set");
    } else {
        Log.e(TAG, "No start level service " + level);
    }
}

现在可以安装并启动bundle了

setInitlevel(1);
installBundle("event_all-3.0.4.jar");
startBundle("event_all-3.0.4.jar");
// install/start other bundles...

setStartLevel(10);

try {
    mFramework.start();
} catch (BundleException be) {
    Log.e(TAG, be.toString());
    // framework start failed
}

Log.d(TAG, "OSGi framework running, state: " + mFramework.getState());

问题

如果你按照上文所述一步步做下来了,你可能会发现还是没法跑起来。由于framework的classloader是在运行期加载的bundle文件,Dalvik虚拟机会试图将优化过的dex类文件放到一个系统目录下面/data/dalvik-cache,但是没有root权限的普通应用程序是不能写入那儿的。

下回将如何解决这个问题。

然后就可以通过命令dexify assets/bundles/*将bundles转换为dex文件。如果是按照Knopflerfish的编译的Knopflerfish,那么不需要将这些bundle的jar文件dex化,但是必须从knopflerfish的framework.jar文件中去掉classes.dex。

via

上一篇文章
这里
教程
source