reworking in new droidgap lite

This commit is contained in:
brianleroux 2010-08-30 15:57:07 -07:00
parent 2384714138
commit 06779773dd
54 changed files with 2094 additions and 215 deletions

1
.gitignore vendored
View File

@ -1,5 +1,4 @@
default.properties
bin
gen
assets/www/phonegap.js
local.properties

150
bin/droidgap Executable file
View File

@ -0,0 +1,150 @@
#!/usr/bin/env ruby
ROOT = File.expand_path(File.dirname(__FILE__).gsub('bin',''))
require 'fileutils'
require File.join(ROOT, "lib", "generate.rb")
require File.join(ROOT, "lib", "package.rb")
require File.join(ROOT, "lib", "run.rb")
require File.join(ROOT, "lib", "update.rb")
# ---------------------------------------------------------- #
# #
# command line interface #
# #
# ---------------------------------------------------------- #
# droidgap gen [app name]
Generate.new(ARGV[1]) if ARGV.first == 'gen'
# droidgap pkg [path to phonegap project]
Package.new(ARGV[1]) if ARGV.first == 'pkg'
# droidgap run [optional directory]
Run.new(ARGV[1]) if ARGV.first == 'run'
# droidgap update [params]
Update.new if ARGV.first == 'update'
# droidgap log
if ARGV.first == 'log'
$stdout.sync = true
IO.popen('adb logcat') do |f|
until f.eof?
puts f.gets
end
end
end
puts "droidgap ship not implemented" if ARGV.first == 'ship'
if ARGV.first.nil? || ARGV.first == 'help'
help = <<-EOF
DroidGap: PhoneGap/Android Dev Script
-------------------------------------
Useful utilities for devlopers building mobile apps using PhoneGap for Android.
Usage:
droidgap <command> <parameters>
Commands:
help ..... See this message. Type help <command name> to see specific help topics.
gen ...... Generate an example PhoneGap application to current directory.
pkg ...... Creates an Android compatible project from a www folder. Careful, this clobbers previous packaging.
run ...... Installs a valid PhoneGap Project to first device found.
log ...... Attach a logger that listens for console.log statements.
update ... Copy a fresh phonegap.jar and phonegap.js into a valid PhoneGap/Android project.
ship ..... Build and sign an APK suitable for submission to an Android Marketplace.
Quickstart:
$ droidgap gen example
$ cd example
$ droidgap run
Now you can launch your app and optionally start a logger with:
$ droidgap log
EOF
gen = <<-EOF
DroidGap Generate
-----------------
Generate an example PhoneGap application to path supplied or current working directory if none is supplied.
Usage:
droidgap gen [path]
EOF
run = <<-EOF
DroidGap Run
------------
Launches PhoneGap project to first device found and attaches a logger that listens for console.log statements.
Usage:
droidgap run <path>
EOF
ship = <<-EOF
DroidGap Ship
-------------
Build and sign an APK suitable for submission to an Android Marketplace.
Usage:
droidgap ship <path>
EOF
log = <<-EOF
DroidGap Log
-------------
Launches LogCat
Usage:
droidgap log
EOF
pkg = <<-EOF
DroidGap Package
----------------
Creates an Android compatable project from a PhoneGap project. For example, if you have MyProject with index.html this comamdn will create MyProject-android.
Usage:
droidgap pkg <path>
EOF
update = <<-EOF
Update: Builds the JS and PhoneGap Android jar file and copies them to your project.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
path ............... The path to generate the Android application.
EOF
puts ARGV[1].nil? ? help : eval(ARGV[1])
end

179
droidgap
View File

@ -1,179 +0,0 @@
#!/usr/bin/env ruby
require 'fileutils'
# ./droidgap /Users/brianleroux/Code/android-sdk-mac MyApp com.westcoastlogic example /Users/brianleroux/Desktop/MyApp
class Build
attr_reader :android_sdk_path, :name, :pkg, :www, :path
def initialize(*a)
@android_sdk_path, @name, @pkg, @www, @path = a
@android_dir = File.expand_path(File.dirname(__FILE__))
@framework_dir = File.join(@android_dir, "framework")
end
# runs the build script
def run
build_jar
create_android
include_www
generate_manifest
copy_libs
add_name_to_strings
write_java
puts "Complete!"
end
# removes local.properties and recreates based on android_sdk_path
# then generates framework/phonegap.jar
def build_jar
puts "Building the JAR..."
%w(local.properties phonegap.js phonegap.jar).each do |f|
FileUtils.rm File.join(@framework_dir, f) if File.exists? File.join(@framework_dir, f)
end
open(File.join(@framework_dir, "local.properties"), 'w') do |f|
f.puts "sdk.dir=#{ @android_sdk_path }"
end
Dir.chdir(@framework_dir)
`ant jar`
Dir.chdir(@android_dir)
end
# runs android create project
# TODO need to allow more flexible SDK targetting
# TODO validate Android SDK
# TODO fix 'android' shell call so that it works on Windows. Can't prepend android command with path to it.
def create_android
android_exec = File.join(@android_sdk_path, "tools", "android");
target_id = 8
puts "Creating Android project for target level #{ target_id }"
`android create project -t #{ target_id } -k #{ @pkg } -a #{ @name } -n #{ @name } -p #{ @path }`
end
def include_www
puts "Adding www folder to project..."
FileUtils.mkdir_p File.join(@path, "assets", "www")
FileUtils.cp_r File.join(@www, "."), File.join(@path, "assets", "www")
end
# creates an AndroidManifest.xml for the project
def generate_manifest
puts "Generating manifest..."
manifest = ""
open(File.join(@framework_dir, "AndroidManifest.xml"), 'r') do |old|
manifest = old.read
manifest.gsub! 'android:versionCode="5"', 'android:versionCode="1"'
manifest.gsub! 'package="com.phonegap"', "package=\"#{ @pkg }\""
manifest.gsub! 'android:name=".StandAlone"', "android:name=\".#{ @name }\""
manifest.gsub! 'android:minSdkVersion="5"', 'android:minSdkVersion="3"'
end
open(File.join(@path, "AndroidManifest.xml"), 'w') { |x| x.puts manifest }
end
# copies stuff from framework into the project
# TODO need to allow for www import inc icon
def copy_libs
puts "Copying over libraries and assets and creating phonegap.js..."
framework_res_dir = File.join(@framework_dir, "res")
app_res_dir = File.join(@path, "res")
FileUtils.mkdir_p File.join(@path, "libs")
FileUtils.cp File.join(@framework_dir, "phonegap.jar"), File.join(@path, "libs")
FileUtils.mkdir_p File.join(app_res_dir, "values")
FileUtils.cp File.join(framework_res_dir, "values","strings.xml"), File.join(app_res_dir, "values", "strings.xml")
FileUtils.mkdir_p File.join(app_res_dir, "layout")
%w(main.xml).each do |f|
FileUtils.cp File.join(framework_res_dir, "layout", f), File.join(app_res_dir, "layout", f)
end
%w(drawable-hdpi drawable-ldpi drawable-mdpi).each do |e|
FileUtils.mkdir_p File.join(app_res_dir, e)
FileUtils.cp File.join(framework_res_dir, "drawable", "icon.png"), File.join(app_res_dir, e, "icon.png")
end
# concat JS and put into www folder.
js_dir = File.join(@framework_dir, "assets", "js")
phonegapjs = IO.read(File.join(js_dir, 'phonegap.js.base'))
Dir.new(js_dir).entries.each do |script|
next if script[0].chr == "." or script == "phonegap.js.base"
phonegapjs << IO.read(File.join(js_dir, script))
phonegapjs << "\n\n"
end
File.open(File.join(@path, "assets", "www", "phonegap.js"), 'w') {|f| f.write(phonegapjs) }
end
# puts app name in strings
def add_name_to_strings
puts "Adding some application name to strings.xml..."
x = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
<resources>
<string name=\"app_name\">#{ @name }</string>
<string name=\"go\">Snap</string>
</resources>
"
open(File.join(@path, "res", "values", "strings.xml"), 'w') do |f|
f.puts x.gsub(' ','')
end
end
# this is so fucking unholy yet oddly beautiful
# not sure if I should thank Ruby or apologize for this abusive use of string interpolation
def write_java
puts "Writing application Java code..."
j = "
package #{ @pkg };
import android.app.Activity;
import android.os.Bundle;
import com.phonegap.*;
public class #{ @name } extends DroidGap
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.loadUrl(\"file:///android_asset/www/index.html\");
}
}
"
code_dir = File.join(@path, "src", @pkg.gsub('.', File::SEPARATOR))
FileUtils.mkdir_p(code_dir)
open(File.join(code_dir, "#{@name}.java"),'w') { |f| f.puts j.gsub(' ','') }
end
#
end
if ARGV.length == 5
Build.new(*ARGV).run
else
puts <<-EOF
DroidGap: PhoneGap/Android Project Generator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creates a fresh app for hybrid mobile web hacking. Delicious robot!
Usage:
./droidgap <android_sdk_path> <name> <package_name> <www> <path>
Params:
android_sdk_path ... The path to your Android SDK install.
name ............... The name of your application.
package_name ....... The name of your package (For example: com.nitobi.demo)
www ................ The path to your www folder. (Wherein your HTML, CSS and JS app is.)
path ............... The path to generate the Android application.
EOF
end

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

25
lib/generate.rb Normal file
View File

@ -0,0 +1,25 @@
# ProjectName
# |
# |-tmp ......... Temporary directory for generated projects to launch into emulators or devices. Ignore.
# | '-android ... A generated Android project.
# |
# |-opt ......... Optional platform specific code. Plugins install native code here.
# | |-android ... Java files
# | '-iphone .... Objective C
# |
# |-bin ......... Generated applications.
# | '-android ... project.apk
# |
# '-www ......... html, css and javascript (optional config.xml for additional properties)
#
class Generate
def initialize(name)
if name.nil?
puts "You need to supply a name to generate a project. Try this:\n\ndroidgap gen MyApp\n\n"
return
end
from = File.join ROOT, "example"
to = File.join FileUtils.pwd, name
FileUtils.cp_r from, to
end
end

Binary file not shown.

206
lib/package.rb Normal file
View File

@ -0,0 +1,206 @@
# Package
#
# Generates an Android project from a valid PhoneGap project directory and puts it in ../[PROJECT NAME]-android
#
# TODO ensure the phonegap.js file is overwritten every single time into the correct tmp dir
#
class Package
attr_reader :name, :pkg, :www, :path
def initialize(path)
read_config(path)
clobber
build_jar
create_android
include_www
generate_manifest
copy_libs
add_name_to_strings
write_java
end
def read_config(path)
# if no path is supplied uses current directory for project
path = FileUtils.pwd if path.nil?
# if a www is found use it for the project
path = File.join(path, 'www') if File.exists? File.join(path, 'www')
# ensure an index.html
raise 'No index.html found!' unless File.exists? File.join(path, 'index.html')
# setup default vars
@name = path.split("/").last
@path = File.join(path, '..', "#{ name }-android") # File.join(path, "tmp", "android")
@www = path # File.join(path, 'www')
@name = path.split('/').last
@pkg = "com.phonegap.tmp#{ Time.now.usec }" # ensure a unique pkg
# android sdk discovery ... could be better
@android_sdk_path = `which android`.gsub('/tools/android','')
@android_dir = File.expand_path(File.dirname(__FILE__).gsub('lib',''))
@framework_dir = File.join(@android_dir, "framework")
# read in www/config.xml and kick off package
@config = {}
config_file = File.join(@www, 'config.xml')
if File.exists?(config_file)
require 'rexml/document'
f = File.new config_file
doc = REXML::Document.new(f)
@config[:id] = doc.root.attributes["id"]
@config[:version] = doc.root.attributes["version"]
doc.root.elements.each do |n|
@config[:name] = n.text if n.name == 'name'
@config[:description] = n.text if n.name == 'description'
@config[:icon] = n.attributes["src"] if n.name == 'icon'
@config[:content] = n.attributes["src"] if n.name == 'content'
if n.name == "preference" && n.attributes["name"] == 'javascript_folder'
@config[:js_dir] = n.attributes["value"]
end
end
# extract android specific stuff
@config[:versionCode] = doc.elements["//android:versionCode"] ? doc.elements["//android:versionCode"].text : 3
@config[:minSdkVersion] = doc.elements["//android:minSdkVersion"] ? doc.elements["//android:minSdkVersion"].text : 1
# will change the name from the directory to the name element text
@name = @config[:name] if @config[:name]
# set the icon from the config
@icon = File.join(@www, @config[:icon])
# sets the app js dir where phonegap.js gets copied
@app_js_dir = @config[:js_dir] ? @config[:js_dir] : ''
# sets the start page
@content = @config[:content] ? @config[:content] : 'index.html'
else
# set to the default icon location if not in config
@icon = File.join(@www, 'icon.png')
@app_js_dir = ''
@content = 'index.html'
end
end
# kills and replaces tmp/android
def clobber
FileUtils.rm_r(@path) if File.exists? @path
FileUtils.mkdir_p @path
end
# removes local.properties and recreates based on android_sdk_path
# then generates framework/phonegap.jar
def build_jar
%w(local.properties phonegap.js phonegap.jar).each do |f|
FileUtils.rm File.join(@framework_dir, f) if File.exists? File.join(@framework_dir, f)
end
open(File.join(@framework_dir, "local.properties"), 'w') do |f|
f.puts "sdk.dir=#{ @android_sdk_path }"
end
Dir.chdir(@framework_dir)
`ant jar`
Dir.chdir(@android_dir)
end
# runs android create project
# TODO need to allow more flexible SDK targetting via config.xml
def create_android
target_id = `android list targets | grep id:`.split("\n").last.match(/\d/).to_a.first
`android create project -t #{ target_id } -k #{ @pkg } -a #{ @name } -n #{ @name.gsub(' ','') } -p #{ @path }`
end
# copies the project/www folder into tmp/android/www
def include_www
FileUtils.mkdir_p File.join(@path, "assets", "www")
FileUtils.cp_r File.join(@www, "."), File.join(@path, "assets", "www")
end
# creates an AndroidManifest.xml for the project
def generate_manifest
manifest = ""
open(File.join(@framework_dir, "AndroidManifest.xml"), 'r') do |old|
manifest = old.read
manifest.gsub! 'android:versionCode="5"', 'android:versionCode="1"'
manifest.gsub! 'package="com.phonegap"', "package=\"#{ @pkg }\""
manifest.gsub! 'android:name=".StandAlone"', "android:name=\".#{ @name.gsub(' ','') }\""
manifest.gsub! 'android:minSdkVersion="5"', 'android:minSdkVersion="3"'
end
open(File.join(@path, "AndroidManifest.xml"), 'w') { |x| x.puts manifest }
end
# copies stuff from src directory into the android project directory (@path)
def copy_libs
framework_res_dir = File.join(@framework_dir, "res")
app_res_dir = File.join(@path, "res")
# copies in the jar
FileUtils.mkdir_p File.join(@path, "libs")
FileUtils.cp File.join(@framework_dir, "phonegap.jar"), File.join(@path, "libs")
# copies in the strings.xml
FileUtils.mkdir_p File.join(app_res_dir, "values")
FileUtils.cp File.join(framework_res_dir, "values","strings.xml"), File.join(app_res_dir, "values", "strings.xml")
# drops in the layout files: main.xml and preview.xml
FileUtils.mkdir_p File.join(app_res_dir, "layout")
%w(main.xml).each do |f|
FileUtils.cp File.join(framework_res_dir, "layout", f), File.join(app_res_dir, "layout", f)
end
# icon file copy
# if it is not in the www directory use the default one in the src dir
@icon = File.join(framework_res_dir, "drawable", "icon.png") unless File.exists?(@icon)
%w(drawable-hdpi drawable-ldpi drawable-mdpi).each do |e|
FileUtils.mkdir_p(File.join(app_res_dir, e))
FileUtils.cp(@icon, File.join(app_res_dir, e, "icon.png"))
end
# concat JS and put into www folder. this can be overridden in the config.xml via @app_js_dir
js_dir = File.join(@framework_dir, "assets", "js")
phonegapjs = IO.read(File.join(js_dir, 'phonegap.js.base'))
Dir.new(js_dir).entries.each do |script|
next if script[0].chr == "." or script == "phonegap.js.base"
phonegapjs << IO.read(File.join(js_dir, script))
phonegapjs << "\n\n"
end
File.open(File.join(@path, "assets", "www", @app_js_dir, "phonegap.js"), 'w') {|f| f.write(phonegapjs) }
end
# puts app name in strings
def add_name_to_strings
x = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
<resources>
<string name=\"app_name\">#{ @name }</string>
<string name=\"go\">Snap</string>
</resources>
"
open(File.join(@path, "res", "values", "strings.xml"), 'w') do |f|
f.puts x.gsub(' ','')
end
end
# this is so fucking unholy yet oddly beautiful
# not sure if I should thank Ruby or apologize for this abusive use of string interpolation
def write_java
j = "
package #{ @pkg };
import android.app.Activity;
import android.os.Bundle;
import com.phonegap.*;
public class #{ @name.gsub(' ','') } extends DroidGap
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.loadUrl(\"file:///android_asset/www/#{ @content }\");
}
}
"
code_dir = File.join(@path, "src", @pkg.gsub('.', File::SEPARATOR))
FileUtils.mkdir_p(code_dir)
open(File.join(code_dir, "#{ @name.gsub(' ','') }.java"),'w') { |f| f.puts j.gsub(' ','') }
end
#
end

67
lib/run.rb Normal file
View File

@ -0,0 +1,67 @@
#
# Run
# ---
#
# A handy machine that does the following:
#
# - packages www to a valid android project in tmp/android
# - builds tmp/android project into an apk
# - installs apk onto first device found
# - if there is no device attached it will start an emulator with the first avd found
# - TODO install apk into now running emulator... need to find way to wait for it to have started
# - TODO if no avds present it will attempt to create one
#
class Run
# if no path is supplied uses current directory for project
def initialize(path)
puts 'packaging www as phonegap/android project in ./tmp/android...'
@pkg = Package.new(path)
@apk = File.join(@pkg.path, "bin", "#{ @pkg.name.gsub(' ','') }-debug.apk")
build_apk
first_device.nil? ? start_emulator : install_to_device
end
def build_apk
puts 'building apk...'
`cd #{ @pkg.path }; ant debug;`
end
def install_to_device
puts 'installing to device...'
`cd #{ @pkg.path }; ant install;`
end
def start_emulator
puts "No devices attached. Starting emulator w/ first avd...\n"
$stdout.sync = true
IO.popen("emulator -avd #{ first_avd } -logcat all") do |f|
until f.eof?
puts f.gets
if f.gets.include? 'Boot is finished'
#IO.popen("cd #{ @pkg.path }; ant install;") do |f|
# puts f.gets
#end
puts "\n\nEMULATOR IS NOW RUNNING!\n\n"
puts "install your app by running: "
puts "cd #{ @pkg.path }; ant install;"
end
end
end
end
# helpers
def first_device
fd = `adb devices`.split("\n").pop()
if fd == 'List of devices attached '
nil
else
fd.gsub('device','')
end
end
def first_avd
`android list avd | grep "Name: "`.gsub('Name: ','').strip
end
#
end

43
updategap → lib/update.rb Executable file → Normal file
View File

@ -1,22 +1,18 @@
#!/usr/bin/env ruby
require 'fileutils'
# ./droidgap /Users/brianleroux/Code/android-sdk-mac MyApp com.westcoastlogic example /Users/brianleroux/Desktop/MyApp
class Build
class Update
attr_reader :android_sdk_path, :path
def initialize(*a)
@android_sdk_path, @path = a
@android_dir = File.expand_path(File.dirname(__FILE__))
@framework_dir = File.join(@android_dir, "framework")
end
# runs the build script
def run
def initialize
@path = FileUtils.pwd
@android_sdk_path = `which android`.gsub('/tools/android','')
@android_dir = File.expand_path(File.dirname(__FILE__))
@framework_dir = File.join(@android_dir, "..", "framework")
# puts "updating #{ @path } with phonegap from #{ @android_dir }"
build_jar
copy_libs
puts "Complete!"
end
end
# removes local.properties and recreates based on android_sdk_path
# then generates framework/phonegap.jar
@ -55,27 +51,4 @@ class Build
File.open(File.join(@path, "assets", "www", "phonegap.js"), 'w') {|f| f.write(phonegapjs) }
end
#
end
if ARGV.length == 2
Build.new(*ARGV).run
else
puts <<-EOF
TestGap: Builds the JS and PhoneGap Android jar file and copies them to your project.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creates a fresh app for hybrid mobile web hacking. Delicious robot!
Usage:
./testgap <android_sdk_path> <path>
Params:
android_sdk_path ... The path to your Android SDK install.
path ............... The path to generate the Android application.
EOF
end