“JavaScript Object Notation (JSON) is a lightweight, text-based, language-independent data interchange format. It was derived from the ECMAScript Programming Language Standard. JSON defines a small set of formatting rules for the portable representation of structured data. JSON can represent four primitive types (strings, numbers, booleans, and null) and two structured types (objects and arrays).”
# Copyright (C) 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
__author__ = 'Damon Kohler <damonkohler@gmail.com>'
import collections
import json
import os
import socket
import sys
PORT = os.environ.get('AP_PORT')
HOST = os.environ.get('AP_HOST')
HANDSHAKE = os.environ.get('AP_HANDSHAKE')
Result = collections.namedtuple('Result', 'id,result,error')
class Android(object):
def __init__(self, addr=None):
if addr is None:
addr = HOST, PORT
self.conn = socket.create_connection(addr)
self.client = self.conn.makefile()
self.id = 0
if HANDSHAKE is not None:
self._authenticate(HANDSHAKE)
def _rpc(self, method, *args):
data = {'id': self.id,
'method': method,
'params': args}
request = json.dumps(data)
self.client.write(request+'\n')
self.client.flush()
response = self.client.readline()
self.id += 1
result = json.loads(response)
if result['error'] is not None:
print result['error']
# namedtuple doesn't work with unicode keys.
return Result(id=result['id'], result=result['result'],
error=result['error'], )
def __getattr__(self, name):
def rpc_call(*args):
return self._rpc(name, *args)
return rpc_call
BeanShell 模块(android.bsh)之实现:
// Copyright (C) 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
import org.json.*;
Android() {
String AP_PORT = System.getenv().get("AP_PORT");
String AP_HOST = System.getenv().get("AP_HOST");
String AP_HANDSHAKE = System.getenv().get("AP_HANDSHAKE");
Socket conn = new Socket(AP_HOST, Integer.decode(AP_PORT));
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream(), "8859_1"), 1 << 13);
OutputStream out_stream = new BufferedOutputStream(
conn.getOutputStream(), 1 << 13);
PrintWriter out = new PrintWriter(
new OutputStreamWriter(out_stream, "8859_1"), true);
int id = 0;
call(String method, JSONArray params) {
JSONObject request = new JSONObject();
request.put("id", id);
request.put("method", method);
request.put("params", params);
out.write(request.toString() + "\n");
out.flush();
String data = in.readLine();
if (data == null) {
return null;
}
return new JSONObject(data);
}
call(String method) {
JSONArray args = new JSONArray();
call(method, args);
}
call(String method, Object arg1) {
JSONArray args = new JSONArray();
args.put(arg1);
call(method, args);
}
call(String method, Object arg1, Object arg2) {
JSONArray args = new JSONArray();
args.put(arg1);
args.put(arg2);
call(method, args);
}
call(String method, Object arg1, Object arg2, Object arg3) {
JSONArray args = new JSONArray();
args.put(arg1);
args.put(arg2);
args.put(arg3);
call(method, args);
}
call(String method, Object arg1, Object arg2, Object arg3, Object arg4) {
JSONArray args = new JSONArray();
args.put(arg1);
args.put(arg2);
args.put(arg3);
args.put(arg4);
call(method, args);
}
JSONArray handshake = new JSONArray();
handshake.put(AP_HANDSHAKE);
call("_authenticate", handshake);
return this;
}
JavaScript 模块(android.js)之实现:
/* * Copyright 2009 Brice Lambson * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */
var AP_PORT = java.lang.System.getenv("AP_PORT");
var AP_HOST = java.lang.System.getenv("AP_HOST");
var AP_HANDSHAKE = java.lang.System.getenv("AP_HANDSHAKE");
load('/sdcard/com.googlecode.rhinoforandroid/extras/rhino/json2.js');
function Android() {
this.connection = new java.net.Socket(String(AP_HOST), AP_PORT),
this.input = new java.io.BufferedReader(
new java.io.InputStreamReader(this.connection.getInputStream(), "8859_1"),
1 << 13),
this.output = new java.io.PrintWriter(new java.io.OutputStreamWriter(
new java.io.BufferedOutputStream(this.connection.getOutputStream(),
1 << 13),
"8859_1"), true),
this.id = 0,
this.rpc = function(method, args) {
this.id += 1;
var request = JSON.stringify({'id': this.id, 'method': method,
'params': args});
this.output.write(request + '\n');
this.output.flush();
var response = this.input.readLine();
return eval("(" + response + ")");
},
this.__noSuchMethod__ = function(id, args) {
var response = this.rpc(id, args);
if (response.error != null) {
throw response.error;
}
return response.result;
}
this._authenticate(String(AP_HANDSHAKE));
}
android-cruft(ndk-to-sl4a.c)之C语言实现:
// Released into the public domain, 15 August 2010
// This program demonstrates how a C application can access some of the Android
// API via the SL4A (Scripting Languages for Android, formerly "ASE", or Android
// Scripting Environment) RPC mechanism. It works either from a host computer
// or as a native binary compiled with the NDK (rooted phone required, I think)
// SL4A is a neat Android app that provides support for many popular scripting
// languages like Python, Perl, Ruby and TCL. SL4A exposes a useful subset of
// the Android API in a clever way: by setting up a JSON RPC server. That way,
// each language only needs to implement a thin RPC client layer to access the
// whole SL4A API.
// The Android NDK is a C compiler only intended for writing optimized
// subroutines of "normal" Android apps written in Java. So it doesn't come
// with any way to access the Android API.
// This program uses the excellent "Jansson" JSON library to talk to SL4A's
// RPC server, effectively adding native C programs to the list of languages
// supported by SL4A.
// To try it, first install SL4A: http://code.google.com/p/android-scripting/
//
// Start a private server with View->Interpreters->Start Server
//
// Note the port number the server is running on by pulling down the status
// bar and tapping "SL4A service".
// This program works just fine as either a native Android binary or from a
// host machine.
// ------------
// To compile on an ordinary linux machine, first install libjansson. Then:
// $ gcc -ljansson ndk-to-sl4a.c -o ndk-to-sl4a
// To access SL4A on the phone use "adb forward tcp:XXXXX tcp:XXXXX" to port
// forward the SL4A server port from your host to the phone. See this
// page for more details:
// http://code.google.com/p/android-scripting/wiki/RemoteControl
// ------------
// To compile using the NDK:
// 1. Make sure you can compile "Hello, world" using the NDK. See:
// http://credentiality2.blogspot.com/2010/08/native-android-c-program-using-ndk.html
//
// 2. If you followed the above instructions, you have a copy of the agcc.pl
// wrapper that calls the NDK's gcc compiler with the right options for
// standalone apps.
//
// 3. Unpack a fresh copy of the jansson sources. Tell configure to build for
// Android:
//
// $ CC=agcc.pl ./configure --host=arm
// $ make
//
// 4. Cross your fingers and go! (I'm quite certain there's a more elegant
// way to do this)
//
// $ agcc.pl -I/path/to/jansson-1.3/src -o ndk-to-sl4a-arm ndk-to-sl4a.c /path/to/jansson-1.3/src/*.o
//
// 5. Copy to the phone and run it with the port of the SL4A server!
#include <stdio.h>
#include <jansson.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
// This mimics SL4A's android.py, constructing a JSON RPC object and
// sending it to the SL4A server.
int sl4a_rpc(int socket_fd, char *method, json_t *params) {
static int request_id = 0; // monotonically increasing counter
json_t *root = json_object();
json_object_set(root, "id", json_integer(request_id));
request_id++;
json_object_set(root, "method", json_string(method));
if (params == NULL) {
params = json_array();
json_array_append(params, json_null());
}
json_object_set(root, "params", params);
char *command = json_dumps(root, JSON_PRESERVE_ORDER | JSON_ENSURE_ASCII);
printf("command string:'%s'\n", command);
write(socket_fd, command, strlen(command));
write(socket_fd, "\n", strlen("\n"));
// At this point we just print the response, but really we should buffer it
// up into a single string, then pass it to json_loads() for decoding.
printf("Got back:\n");
while (1) {
char c;
read(socket_fd, &c, 1);
printf("%c", c);
if (c == '\n') {
break;
}
}
fflush(stdout);
return 0;
}
// This function is just boilerplate TCP socket setup code
int init_socket(char *hostname, int port) {
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
perror("Error creating socket");
return 0;
}
struct hostent *host = gethostbyname(hostname);
if (host == NULL) {
perror("No such host");
return -1;
}
struct sockaddr_in socket_address;
int i;
for (i=0; i < sizeof(socket_address); i++) {
((char *) &socket_address)[i] = 0;
}
socket_address.sin_family = AF_INET;
for (i=0; i < host->h_length; i++) {
((char *) &socket_address.sin_addr.s_addr)[i] = ((char *) host->h_addr)[i];
}
socket_address.sin_port = htons(port);
if (connect(socket_fd, (struct sockaddr *) &socket_address, sizeof(socket_address)) < 0) {
perror("connect() failed");
return -1;
}
return socket_fd;
}
main(int argc, char **argv) {
int port = 0;
if (argc != 2) {
printf("Usage: %s port\n", argv[0]);
return 1;
}
port = atoi(argv[1]);
int socket_fd = init_socket("localhost", port);
if (socket_fd < 0) return 2;
json_t *params = json_array();
json_array_append(params, json_string("w00t!"));
sl4a_rpc(socket_fd, "makeToast", params);
}
Hello Android之多语言实现
在文章的最后,给大家一个经典的Hello Android多语言实现,O(∩_∩)O哈哈~
BeanShell:
source("/sdcard/com.googlecode.bshforandroid/extras/bsh/android.bsh");
droid = Android();
droid.call("makeToast", "Hello Android!");
JavaScript:
load("/sdcard/com.googlecode.rhinoforandroid/extras/rhino/android.js");
var droid = new Android();
droid.makeToast("Hello Android!");
Perl:
use Android;
my $a = Android-->new();
$a-->makeToast("Hello Android!");
Python:
import android
andy = android.Android()
andy.makeToast("Hello Android!")
Ruby:
droid = Android.new
droid.makeToast "Hello Android!"
TCL:
package require android
set android [android new]
$android makeToast "Hello Android!"