注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Allen小笔记

有时会忘记努力...

 
 
 

日志

 
 

Android ASE  

2009-12-18 19:26:00|  分类: Android |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
                                                                                                         Android, ASE, Script

The Android Scripting Environment (ASE) brings scripting languages to Android by allowing you to edit and execute scripts and interactive interpreters directly on the Android device. These scripts have access to many of the APIs available to full-fledged Android applications, but with a greatly simplified interface that makes it easy to:
  • Handle intents
  • Start activities
  • Make phone calls
  • Send text messages
  • Scan bar codes
  • Poll location and sensor data
  • Use text-to-speech
  • And more
总之, 是说,Android 脚本环境.
I am a coder, 开始RTFS.给出下面的一个ASE的Architecture.
Android ASE - 一切的阅读都是误读 - Allen小笔记
我的手迹,嘿嘿...看到这张图就清晰了吧,其实也就是弄了个Client端和Server端.这俩端用JSON(去这里,解释的很清楚)去通信.至于Server端,完全就是Android的那一套了,Java 通过JNI调用C/C++.
有了ASE,就有了快速使用Script的环境,当然,我们也完全不这么做,下面我就说说自己怎么做这一套东西.
我比较熟悉Lua,我就说说Lua吧.
Lua和C/C++有很好的交互能力.所以,我们可以不要JSON中间这一层.完全可以自己编译出一个Lua interpreter放到Android上,让interpreter直接跑在Linux Kernel上面.然后让lua和你想要的任何C/C++函数进行交互.
 Okay,怎么编译Lua(可以单独写一篇文章了),我以后再说,Build Lua code on Linux and Windows是很简单的事情.但是在Android上面就相对来说麻烦很多.
实际上, 有两种方式来进行Lua 和C/C++交互.
第一种:在C/C++中把lua的static library 或者shared library包含进来.比如:lua.so 或者 lua.a
第二种:把C/C++编译成Shared library, 然后Lua 使用package.load()或者直接require("shared library file")
我贴出第一种情况下的代码(不能运行,只是个试例):
-------------------------C Code-------------------------
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
 
//=============================================
// Global Variables
//=============================================
lua_State *L;
//=============================================
// Lua Functions
//=============================================
double f( double x, double y )
{
    double ret;
    lua_getglobal( L, "f");        
    lua_pushnumber( L,x);         
    lua_pushnumber( L,y);          
    lua_call( L, 2, 1);           
    ret = lua_tonumber( L, -1);    
    lua_pop( L, 1);                      
    return ret;
}
 
 
//=========================================
 
int LuaC_PrintMessage( lua_State *L)
{
    char Message[256] = "";
    int i;
    int j;
    int n = lua_gettop(L);
    for ( i = 1, j = 0; i <= n ; i++)
    {
        if( lua_isstring( L, i))
        strcpy( Message, lua_tostring( L, i));
    }
    printf("PrintMessage::%s\n",Message);
    return 0;
}
 
//=========================================
 
 
//==============================================
// Main Functions
//==============================================
int main()
{
    int error;
    const char *p;// for debug
    char werr[256]={};//for debug
    char result[256]={};//for result
 
    L = lua_open();    
    luaopen_base(L);  
    luaL_openlibs(L);   
    /*
    luaopen_table(L);   
    luaopen_io(L);         
    luaopen_string(L);  
    luaopen_math(L);   
   */
    lua_register( L, "LuaC_PrintMessage", LuaC_PrintMessage);
 
 
    /* load the script */
    if(luaL_dofile(L,"/sdcard/test.lua")!=0)
    {
        FILE *fi=fopen("/sdcard/test.lua","r");
        p=lua_tostring(L,-1);
        printf("%s\n",p);
        free(p);
    }
    double ret = f( 10, 3.141592653);
    sprintf(result,"Result=%2.9f",ret);//2+9+1 means 12 charactors
    printf("%s\n",result);
    return 0;
}

------------------------------------------------------------lua 脚本-------------------------------------------------------------------
LuaC_PrintMessage("Call C Function");
function f(x,) return x+y end
第二种情况类似,我就不重复了.

Updated.
实际上,第一次我画的Architechture有一点问题.Focus on Android端.
Android ASE - 一切的阅读都是误读 - Allen小笔记
所以,流程是这样的.首先,建立 AndroidProxy Service,它会负责Run JsonRpcServer.这个Server非常重要,它负责监听以及和Script PC Client 端通信.那么这里有两个很重要的Thread, 第一是Thread 用于Listen Socket, 当Accept socket的时候,就会创建另一个线程去Connect to the Client.JsonPpcServer还有两个重要的函数,分别是StartPublic 和Start Local. StartPublic()建立Remote 通信,远程通信主要是负责监听PC端的脚本;StartLocal()建立Local通信,本地通信的作用主要是用来:监听Android上解释执行的脚本.也就是说:
无论本地还是远端的脚本都是通过JsonRpcServer来统一调用Android JAVA API的
AndroidProxyService含有AndroidProxy类.这个类的主要作用就是负责调用AndroidFacade类中,封装好了的,提供给Script调用的函数.
也就是说干活的代码这这里(当然,底层才是真正的工作的代码,但是我们在这里这么理解他).
AndroidProxy类中,还包含有notification和notification manager之类的东西.notification就是我们在运行ASE时start service时,模拟器或者手机顶端的提示信息.这里包含了一个很重要的信息:IP和Port号.其中Port号就是Run Scripts Externally 中的Remote的端口号.代码如下:
adb forward tcp:<local_port> tcp:<remote_port>
local port超过1024就可以了, remote port就是notification中的port号.
当然,还有一步也是一定要做的:
export AP_PORT local_port
我们来看一下, ASE中Android.py的源代码,
PORT = os.environ.get('AP_PORT')
class Android(object):
  def __init__(self, addr=None):
    if addr is None:
      addr = 'localhost', PORT
    self.conn = socket.create_connection(addr)
    self.client = self.conn.makefile()
    self.id = 0
可以看到第一句话就是从:系统中拿到AP_PORT环境变量,为以后建立socket打下基础.
好像,讲的离题了点.继续,JsonRpcServer.
在这个类中,有很重要的一个方法:
    private JSONObject dispatch(int id, String methodName, JSONArray params) throws JSONException {
    JSONObject result;
    try {
      Method m = mReceiver.getClass().getMethod(methodName, new Class[] { JSONArray.class });
      if (m.isAnnotationPresent(Rpc.class)) {
        result = (JSONObject) m.invoke(mReceiver, new Object[] { params });
      } else {
        throw new Exception();
      }
...
省略非重点.
  这里就是会Call AndroidFacade中函数的地方了.
 所以,理论上,我们只要扩展AndroidFacade中的函数,然后,在AndroidProxy中调用AndroidFacade就Okay了.
然后,ASE源代码中,还包含了ASE这支APK的代码,比较有意思的地方是:Exec.java这类了,里面都是native的函数调用,是用来创建Process的.
 public static native FileDescriptor createSubprocess(String cmd, String arg0, String arg1,
      int[] processId)

这次就写这么多了.
 


Update.

上次说过的方法:PC连接Android Device是透过USB cable的.但是,我上面说过,JsonRpcServer是会Run在Device的呀...而RpcServer实际上不就是个Socket 监听嘛!瞧见了没?Socket, 那实际上来说,不一定要透过USB cable来access android device啊.你用Wifi不也一样的吗?

okay,我们来改造一下android.py这个脚本文件.

 class Android(object):
def __init__(self, addr=None):
if addr is None:
addr = 'localhost', PORT
看到了,这个addr是怎么构成的了吧?google将IP写死了“localhost”.改成:

PORT = os.environ.get('AP_PORT')
IP = os.environ.get('IP')

class Android(object):
def __init__(self, addr=None):
if addr is None:
#addr = 'localhost', PORT
if IP is None:
addr = 'localhost', PORT
else:
addr = IP, PORT

这样,你只要在$shell里面输入(IP和Port当然要根据device的IP和Port来决定啊):
 $ export AP_PORT=43654
$ export IP=192.168.221.20
$ python
你就直接可以经过PC控制device了.

重要更新:
 忘记说明一个很重要的模型。
 在android上,pc控制device是这样子的:1. PC通过Socket 程序(随便什么代码,比如java,python,C)发送到PC的AP_PORT端口上. 2.ADB 使用forward命令将AP_PORT端口的数据或者命令转发到Device上的remote port上.
  评论这张
 
阅读(1865)| 评论(4)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017