40
So you want to build Android apps… without Java? Nick Plante @zapnap brief introduction to Mirah and Pindah)

Building native Android applications with Mirah and Pindah

Embed Size (px)

DESCRIPTION

So you want to build native Android applications without using Java? Here's how.

Citation preview

Page 1: Building native Android applications with Mirah and Pindah

So you want to build Android apps… without Java?

Nick Plante @zapnap

(A brief introduction to Mirah and Pindah)

Page 2: Building native Android applications with Mirah and Pindah

Who?

Nick Plante (not a Java developer)

Zerosum Labs Rails Rumble Rubydoc.info

Chinaccelerator

Contact me! @zapnap on Twitter http://github.com/zapnap

Page 3: Building native Android applications with Mirah and Pindah

Why?

Because you’re a Ruby developer (familiarity).

Because Android is awesome. Because simplicity is elegance.

“Think Different.”

Page 4: Building native Android applications with Mirah and Pindah

Java vs Ruby

Dynamic vs Static Simplicity vs Complexity & Verbosity Less Ceremony

Java is a systems programming language, after all

But… The JVM is an awesome platform Android’s use of the JVM (Dalvik) gives

us options

Page 5: Building native Android applications with Mirah and Pindah

Java Alternatives

Android Scripting Environment (SL4A) Great for scripting; not great for applications Limited access to Android API / GUI Performance issues

Other JVM-based languages: Scala Clojure JRuby Mirah Groovy?

Page 6: Building native Android applications with Mirah and Pindah

JRuby & Mr Ruboto

Ruboto is your friend! JRuby interface / framework for Android

APIs http://ruboto.org

But JRuby runtime overhead is a problem Slow startup (~10 seconds) Large APK size▪ HelloWorld: 3.4MB compressed, 10MB installed

Page 7: Building native Android applications with Mirah and Pindah

Introducing Mirah

Mirah compiles straight to Java bytecode Very fast, no extra overhead

Syntax is very Ruby-ish Statically-typed with local type inference “Ruby with type annotations”

No runtime library Mix and match Java code

Page 8: Building native Android applications with Mirah and Pindah
Page 9: Building native Android applications with Mirah and Pindah

Warning!

Mirah is still a very young language (v0.0.7)

Tooling is very, very alpha Advantage: Eclipse (Java) Redcar looks promising

Compilation errors are very, very not-so-funNativeException: jmeta.SyntaxError: expected Ensure before ' { |a b| Inte' (at line: 16, char: 40)

Page 10: Building native Android applications with Mirah and Pindah

One thing at a time

We’ll get to Android in just a second First let’s see some basic Mirah

syntax…

Page 11: Building native Android applications with Mirah and Pindah

# fib.mirahdef fib(a:int):int if a < 2 a else fib(a-1) + fib(a-2) endend

puts fib(20)

Ruby vs Mirah

# fib.rubydef fib(a) if a < 2 a else fib(a-1) + fib(a-2) endend

puts fib(20)

Parameter type declaration???SRSLY?

Return type can often be inferred.

Page 12: Building native Android applications with Mirah and Pindah

.class output

Produces a java .class $ mirahc fib.mirah public static int fib(int)

Can also produce .java code $ mirahc -j fib.mirah * I have no idea why you would want to

do this.

Page 13: Building native Android applications with Mirah and Pindah

.to_java => “ick”

// Generated from hello.mirahpublic class Hello extends java.lang.Object { public static void main(java.lang.String[] argv) { java.io.PrintStream temp$1 = java.lang.System.out; temp$1.println(Hello.fib(20)); } public static int fib(int a) { return (a < 2) ? (a) : ((Hello.fib((a - 1)) + Hello.fib((a - 2)))); }}

Page 14: Building native Android applications with Mirah and Pindah

Challenges / Major Differences Java stdlib: both a blessing and a curse

List, HashMap, etc▪ arr.get(1) vs arr[0]

Blocks work, but syntactic sugar required For example, List#each can be used (array) But HashMap#each does not exist

No optional arguments, no *splats, no ranges

Page 15: Building native Android applications with Mirah and Pindah

Using Java’s Standard Libraryimport java.util.Collectionsimport java.util.HashMapimport java.util.List

class ListPrinter def print(list:List) puts "first item: #{list.get(0)}" list.each do |item| puts "item: #{item}" end end end

class HashPrinter def print(map:HashMap) map.keySet.each do |key| puts "#{key}: #{map.get(key)}" end end end

map = { 'batman' => 'bruce wayne', 'superman' => 'clark kent' }HashPrinter.new.print(map)

list = ['peter', 'stewie', 'brian']ListPrinter.new.print(list)

Page 16: Building native Android applications with Mirah and Pindah

Get Mirah

# Install JRuby 1.6 if you haven’t already# (or rvm use jruby)

$ jruby –S gem install mirah

$ mirah -e "puts 'hello world'”> hello world

Page 17: Building native Android applications with Mirah and Pindah

Now What?

Page 18: Building native Android applications with Mirah and Pindah

Get the Android SDK

Download and install it: http://developer.android.com/sdk/index.html

Notes on building from the command line: http://developer.android.com/guide/developing/

projects/projects-cmdline.html

Set up your environment (see above): Make sure to set JAVA_HOME, CLASSPATH, and

put your platform-tools directory in your path

Page 19: Building native Android applications with Mirah and Pindah

Android SDK / Virtual Devices

Page 20: Building native Android applications with Mirah and Pindah

The anatomy of a typical Android application Activities Intents Manifest File XML Layouts (Views) Services Content Providers

(Lots to learn)

Page 21: Building native Android applications with Mirah and Pindah

Hello Pindah

Garrett, Protoform, Mirahndroid => Pindah

Goals Make it easy to get started with Android + Mirah Make day to day development tasks easier Provide project structure and conventions

Application skeleton generator Rake tasks to hide Ant nastiness

Because XML is pain Use Rake to compile / debug / install / etc

Page 22: Building native Android applications with Mirah and Pindah

What Pindah Does NOT Do

No “pretty” wrappers for Android APIs You must learn the APIs to work

effectively

Does not provide alternatives to XML-based Manifest or view layouts https://github.com/objo/droid-views

Page 23: Building native Android applications with Mirah and Pindah

Get Pindah

# For more information, see# http://github.com/mirah/pindah$ jruby –S gem install pindah

# Generate an Android application skeleton$ pindah create org.example.hello

[/path/to/hello_world] [HelloActivity]

Page 24: Building native Android applications with Mirah and Pindah

Android App Skeleton

├── AndroidManifest.xml├── Rakefile├── libs├── res│   ├── drawable-hdpi│   │   └── ic_launcher.png│   ├── drawable-ldpi│   │   └── ic_launcher.png│   ├── drawable-mdpi│   │   └── ic_launcher.png│   ├── layout│   │   └── main.xml│   └── values│   └── strings.xml└── src └── org └── example └── hello └── HelloActivity.mirah

Managed for you by Pindah:

• default.properties• build.properties• local.properties• build.xml

Page 25: Building native Android applications with Mirah and Pindah

Pindah Rake Tasks

$ rake -TAndroid SDK Tools Revision 8Project Target: Android 2.1-update1API level: 7

------------------Resolving library dependencies:No library dependencies.

------------------

Importing rules file: tools/ant/main_rules.xmlrake clean # Removes output files created by other targets.rake compile # Compiles project's .mirah files into .class filesrake debug # Builds the application and signs it with a debug key.rake install # Installs/reinstalls the debug package onto a running ...rake javac # Compiles R.java and other gen/ files.rake logcat # Tail logs from a device or a device or emulatorrake release # Builds the application.rake spec # Print the project specrake uninstall # Uninstalls the application from a running emulator or dev...

Page 26: Building native Android applications with Mirah and Pindah

Android Activity Boilerplate

# HelloActivity.mirahpackage org.example.hello

import android.app.Activity

class HelloActivity < Activity def onCreate(state) super state setContentView R.layout.main endend

# HelloActivity.javapackage org.example.hello;

import android.app.Activity;

public class HelloActivity extends Activity{ /** Called when the activity is first

created. */ @Override public void onCreate( Bundle savedInstanceState) { super.onCreate( savedInstanceState); setContentView( R.layout.main); }}

Page 27: Building native Android applications with Mirah and Pindah

Running the Example App$ cd hello_world$ rake install=> WIN.

Page 28: Building native Android applications with Mirah and Pindah

Well, that was boring

Page 29: Building native Android applications with Mirah and Pindah

Slightly More Interesting

More expressive code == visible improvement

Example application “Up or Down?” website testing app http://github.com/zapnap/upordown

Questions: What do Android callbacks look like? How do I leverage 3rd party (Java) libraries? How do I handle exceptions? How does Mirah deal with scope? (it’s weird)

Page 30: Building native Android applications with Mirah and Pindah

Up or Down? Down or Up?

Page 31: Building native Android applications with Mirah and Pindah

Android Listeners (Java)

// Sample button click listener in Java

// Create an anonymous implementation of OnClickListenerprivate OnClickListener mClickListener = new OnClickListener() { public void onClick(View v) { // handle click event }};

protected void onCreate(Bundle savedValues) { ... // Capture our button from layout Button mSubmit = (Button)findViewById(R.id.submit_btn); // Register the onClick listener with the impl above mSubmit.setOnClickListener(mClickListener); ...}

Page 32: Building native Android applications with Mirah and Pindah

StatusActivity + Listenersclass StatusActivity < Activity def onCreate(state) super state setContentView R.layout.main @url = EditText findViewById(R.id.url_txt) @submit = Button findViewById(R.id.submit_btn)

setListeners end

def setListeners this = self # SHORTCUT: click listener must implement onClick @submit.setOnClickListener do |v| status = this.checkSiteStatus(this.getUrl) this.showResult status end end

Scoping for ivars and self is incomplete. Assign a local var within scope.

Easy to add anonymous listeners with this syntax (implements a single method interface)

Page 33: Building native Android applications with Mirah and Pindah

Using External Java LibrariesPut jars in libs folder and import to use. Simple! (must import Android libs too)

import java.net.URLimport java.net.SocketTimeoutException

import org.jsoup.Jsoupimport org.jsoup.nodes.Document

def checkSiteStatus(address:String):String return "Please specify a URL to test" if address.equals('')

begin doc = Jsoup.connect( "http://downforeveryoneorjustme.com/" + address ).get res = doc.select("#container").first.text

Log.d 'StatusActivity', 'Full response from server is: ' + res res.substring(0, res.indexOf('Check another')) rescue SocketTimeoutException => ex "Unable to contact the server. How ironic!” endend

Exception handling works like it does in Ruby. Must import specific exceptions.

Page 34: Building native Android applications with Mirah and Pindah

Wrapping Up: Dialog Example

def getUrl @url.getText.toStringend

def showResult(message:String) alert = AlertDialog.Builder.new(self) alert.setTitle 'Site Test Results’ alert.setMessage message alert.setPositiveButton('OK') do |dialog, w| dialog.dismiss end

alert.showend

Page 35: Building native Android applications with Mirah and Pindah

Android XML Layouts (main.xml)

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textSize="20sp" android:textStyle="bold" android:text="@string/app_title" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textSize="18sp" android:textStyle="bold" android:layout_marginBottom="10dip" android:text="@string/app_subtitle" /> <EditText android:id="@+id/url_txt" android:layout_width="fill_parent" android:singleLine = "true" android:layout_height="wrap_content" android:inputType="textUri" android:hint="@string/url_example" /> <Button android:id="@+id/submit_btn" android:layout_width="140dip" android:layout_marginTop="6dip" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:text="@string/submit_btn" /> </LinearLayout> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:layout_alignParentBottom="true" android:autoLink="web" android:text="@string/powered_by" /></RelativeLayout>

<EditText android:id="@+id/url_txt" android:layout_width="fill_parent" android:singleLine = "true" android:layout_height="wrap_content" android:inputType="textUri" android:hint="@string/url_example" />

more info

app title[ url input ][ button]

Page 36: Building native Android applications with Mirah and Pindah

One More Thing

Android Manifest lists top-level activities and required permissions

Our app requires Internet access Add the permission to

AndroidManifest.xml: <uses-permission android:name="android.permission.INTERNET" />

Page 37: Building native Android applications with Mirah and Pindah

It Works!

Page 38: Building native Android applications with Mirah and Pindah

Ideas for Next Steps

Implement a ProgressDialog And perform the site check in an AsyncTask

Record a log of website test history to a ListView Allow users to browse test history through a

separate Activity Store test history to a local Sqlite database

(and ListAdapter)

Fork me at http://github.com/zapnap/upordown

Page 39: Building native Android applications with Mirah and Pindah

Conclusions (or lack thereof) Mirah is a nice midpoint between Ruby and Java

Well-suited for Dalvik JVM work But still very immature / not yet practical for daily use Opportunity to help push mobile dev forward

Lack of good IDE support Makes working with the (massive) Android API difficult

Debugging is a pain in the butt ADB (Rake logcat) is incredibly useful; learn to use it

I personally still prefer mobile web development ;-) but sometimes native is the way to go!

Page 40: Building native Android applications with Mirah and Pindah

And so it goes

Mirah Language Resources http://mirah.org http://github.com/mirah/mirah

Pindah and Mirah and Android Oh My! http://github.com/mirah/pindah http://github.com/technomancy/garrett (experiments) http://threebrothers.org/brendan (urbanspoon)

General Android Development http://developer.android.com/sdk/index.html http

://developer.android.com/guide/developing/projects/projects-cmdline.html