Mirah is a Ruby-like language that compiles to Java bytecode, allowing Ruby developers to write Android apps without using Java. The document introduces Mirah and Pindah, a framework that makes it easier to develop Android apps in Mirah. It provides an example "Up or Down?" app that checks the status of websites and displays results. While Mirah offers a more Ruby-like syntax, it is still immature and tooling support needs improvement, making large Android app development challenging.
Apidays New York 2024 - The value of a flexible API Management solution for O...
Building native Android applications with Mirah and Pindah
1. So you want to build Android apps… without Java? Nick Plante @zapnap (A brief introduction to Mirah and Pindah)
2. Who? Nick Plante (not a Java developer) Zerosum Labs Rails Rumble Rubydoc.info Chinaccelerator Contact me! @zapnap on Twitter http://github.com/zapnap
3. Why? Because you’re a Ruby developer (familiarity). Because Android is awesome. Because simplicity is elegance. “Think Different.”
4. 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
5. 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?
6. JRuby & MrRuboto 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
7. 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
8.
9. 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-fun NativeException: jmeta.SyntaxError: expected Ensure before ' { |a b| Inte' (at line: 16, char: 40)
10. One thing at a time We’ll get to Android in just a second First let’s see some basic Mirah syntax…
11. # fib.mirah def fib(a:int):int if a < 2 a else fib(a-1) + fib(a-2) end end puts fib(20) Ruby vsMirah Parameter type declaration??? SRSLY? # fib.ruby def fib(a) if a < 2 a else fib(a-1) + fib(a-2) end end puts fib(20) Return type can often be inferred.
12. .class output Produces a java .class $ mirahcfib.mirah public static intfib(int) Can also produce .java code $ mirahc -jfib.mirah * I have no idea why you would want to do this.
13. .to_java => “ick” // Generated from hello.mirah public 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 intfib(int a) { return (a < 2) ? (a) : ((Hello.fib((a - 1)) + Hello.fib((a - 2)))); } }
14. 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#eachcan be used (array) But HashMap#eachdoes not exist No optional arguments, no *splats, no ranges
15. Using Java’s Standard Library import java.util.Collections import java.util.HashMap import 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' => 'brucewayne', 'superman' => 'clarkkent' } HashPrinter.new.print(map) list = ['peter', 'stewie', 'brian'] ListPrinter.new.print(list)
16. 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
18. 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
20. The anatomy of a typical Android application Activities Intents Manifest File XML Layouts (Views) Services Content Providers (Lots to learn)
21. 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
22. 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
23. Get Pindah # For more information, see # http://github.com/mirah/pindah $ jruby –S gem installpindah # Generate an Android application skeleton $pindahcreate org.example.hello [/path/to/hello_world] [HelloActivity]
28. Android Activity Boilerplate # HelloActivity.mirah package org.example.hello import android.app.Activity class HelloActivity < Activity def onCreate(state) super state setContentViewR.layout.main end end # HelloActivity.java package 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); } }
31. 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)
33. Android Listeners (Java) // Sample button click listener in Java // Create an anonymous implementation of OnClickListener private OnClickListenermClickListener = new OnClickListener() { public void onClick(Viewv) { // handle click event } }; protected void onCreate(BundlesavedValues) { ... // Capture our button from layout Button mSubmit = (Button)findViewById(R.id.submit_btn); // Register the onClick listener with theimpl above mSubmit.setOnClickListener(mClickListener); ... }
34. StatusActivity + Listeners class StatusActivity < Activity def onCreate(state) super state setContentViewR.layout.main @url = EditTextfindViewById(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)
35. Using External Java Libraries Put jars in libs folder and import to use. Simple! (must import Android libs too) import java.net.URL import java.net.SocketTimeoutException import org.jsoup.Jsoup import 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!” end end Exception handling works like it does in Ruby. Must import specific exceptions.
36. Wrapping Up: Dialog Example def getUrl @url.getText.toString end 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.show end
38. 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" />
40. 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
41. 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!