This is the first official version of the Postcard App which supports Story 0. The Postcard App is our main demo application for highlighting the Thali Project and its uses, where you can create postcards and sync them to other devices such as from iOS to iOS device or Android device to Android device.
Story 0
Story 0 provides the basic pieces needed to let Android phones sync to other local Android phones and iPhones sync to other local iPhones. Unfortunately, local syncing between Android and iPhones is a nightmare that we will tackle later.
At the bottom of our tech stack on Android is Wi-Fi Direct Service Discovery which we use for finding other Android phones running Thali software and Bluetooth which we use for high bandwidth data exchange between Android phones. See here for more on these choices. One thing we have already learned is that Wi-Fi Direct Service Discovery is seriously broken and will be replaced in future releases.
In the case of iOS we use Bluetooth Low Energy (BLE) for discovery and the multi-peer connectivity framework for high bandwidth data exchange. We detailed our choices which you can read about. The main lesson we learned is that running BLE in the background on iOS is a serious nightmare.
Above both of these discovery and high bandwidth local radio stacks we run Node.js or a variant of it called JXcore. Yes, we are running Node.js on the phone! JXcore is a fork of Node.js that supports running Node.js on Android and iOS, as well as Linux, Mac and Windows. JXcore’s magic comes in two parts. The first part is that they put in an abstraction layer so they can run JavaScript engines other than just V8. Right now they support spider monkey and V8. The second part is that they support being run as a Cordova Plugin that includes a “mobile” library which provides basic functionality that someone writing a node.js app on a mobile device needs. With JXcore we can write the bulk of our logic in JavaScript and use it across both Android and iOS. To make this work we use JXcore’s native API layer to expose the native radio stacks and we put over it a standard Node.js API.
The end result is that we have a node.js level API that can tell the Node.js application when a peer is in the area and let the application open a TCP/IP connection to that peer. In fact we even put in a mux layer so that node.js clients can open as many TCP/IP connections as they want to the peer and we will multiplex them all down to a single connection for transmission over the air using the multiplex Node.js library.
Right now the layer that allows for discovery and connectivity is not broken out on its own but eventually it will be so those who just want to have discovery and connectivity but not the rest of Thali can use it stand alone.
On top of that discovery/connectivity layer we built something we call the replication manager. This is a thin layer of code around the ever amazing PouchDB. PouchDB is a JavaScript implementation of the CouchDB HTTP based multi-master synchronization protocol. It lets us automatically sync between peers and get them into consistent states.
Wrapped around all of this is [Apache Cordova]. In fact our main project, the Thali Cordova Plugin, is actually just a Cordova plugin. We use Cordova for a number of reasons. First, it lets us our customers provide a consistent user experience that can work on both Android and iOS. Second, it provides us with a framework with which to manage our native JXcore dependencies and get them built into apps. Eventually we’ll support using Thali’s infrastructure independently of Cordova but for now you have to use Cordova to use Thali.
Building and Running the Postcard App
Dependencies
Windows Prerequisites
If you are using Windows to build the Postcard App, you will need to use node-gyp to compile leveldown
The following software is required:
- Visual Studio 2013 (note: VS 2015 doesn't appear to work yet)
- Python 2.7.x
Follow the node-gyp installation documentation to ensure that Python is properly set. The easiest way for Python to work is to have it set in your PATH environment variable.
Note that if you have multiple versions of Visual Studio installed then you have to use the '--msvs_version' switch to tell the system to use VS 2013.
$ jx npm install --production --autoremove="*.gz" --msvs_version=2013
Installing Android Studio
To get started, first download Android Studio and follow the instructions below.
Make sure to set your ANDROID_HOME
environment variable:
Mac OS X (put in your ~/.bash_profile
file):
export ANDROID_HOME=~/Library/Android/sdk
export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
Linux (put in your ~/.bashrc
file):
export ANDROID_HOME=/<installation location>/Android/sdk
export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
Windows:
set ANDROID_HOME=C:\<installation location>\Android\sdk
set PATH=%PATH%;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools
JXcore
Follow the instructions at http://jxcore.com/downloads/. Their download page is a little confusing so please pay attention to the section at the top that says in a tiny little font 'Installation'. When you're done, check that the installation worked:
$ jx -jxv
v 0.3.0.7
Install Apache Cordova
Ensure that Apache Cordova is installed globally by using JXcore's jx install
command.
Mac/Linux:
$ sudo jx install -g cordova
Windows:
$ jx install -g cordova
Install Bower
Bower is required to install web app dependencies.
$ npm install -g bower
Hardware
You will need two (it's a peer to peer system) Android devices running at least KitKat. And no, the emulator won't work. We depend on specific radios to work and they aren't in the emulator.
Building the postcard app
git clone -b story_0 https://github.com/thaliproject/postcardapp.git
cd postcardapp
cordova platform add ios
cordova platform add android
cd www/jxcore
jx npm install --production --autoremove "*.gz"
bower install
find ./bower_components -name "*.gz" -type f -delete
cordova build ios
cordova build android
On Windows one needs to use Git Bash or equivalent to run the above commands.
Running in development environment on localhost
You will also need to copy the Thali_CordovaPlugin 'mockmobile.js' script if you want run in development mode. This allows native methods to be called on the desktop when UX testing the web app.
cd www/jxcore
cp -v ../../thaliDontCheckIn/Thali_CordovaPlugin-master/test/www/jxcore/bv_tests/mockmobile.js node_modules/thali/
Known Issues
Getting Discovery Working
First and foremost, service discovery over Wi-Fi Direct is not terribly reliable. It can take anywhere from seconds to minutes to discover another device. Yes, we are working on this (including looking at moving completely over to Bluetooth Low Energy). In the meantime something you can do to improve things is reboot your devices. But otherwise the way to know if discovery actually occurred is by looking at your logcat output. See below for instructions on using logcat. In the log you are looking for something like:
08-07 11:18:47.444 6037-6037/org.thaliproject.postcardapp I/Service searcher﹕ Added service request
08-07 11:18:48.464 6037-6037/org.thaliproject.postcardapp I/Service searcher﹕ Started service discovery
08-07 11:19:47.444 6037-6037/org.thaliproject.postcardapp I/Service searcher﹕ Cleared service requests
You will see this repeat a lot because it turns out that service discovery just kinda stops working after a minute or two so we have to constantly turn it on and off to get it to work. This is one of the reasons why service discovery performance is so awful, it takes time to turn the service on and off and while that is happening we can't be discovered or discover others.
When the other device is found you will see something in the log like:
08-07 11:37:31.092 13884-13884/org.thaliproject.postcardapp I/Service searcher﹕ Found Service, :{ "pi": "90:E7:C4:EA:B0:22","pn": "62","ra": "90:E7:C4:EA:B0:22"}, typeCordovap2p._tcp.local.:
08
And yes, we are going to make this easier. See here and here.
Using logcat
The easiest way in my opinion to use logcat, especially given that there are two devices involved, is to use Android Studio and its logcat viewer. But for masochists out there you can also use logcat via adb. But you have to specify which device you want to get your logcat output from. So first run adb devices
to get a list of your attached devices. Then issue adb -s [id] logcat
where [id] is the device ID you got from adb devices
.
Support for iOS 9
iOS 8 is the current supported platform. But the plan is to move forward to iOS 9 once we have tested everything.
In the meantime, if you have updated to iOS 9 you will need to add an App Transport entry to your Info.plist
until we put a fix in.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPSLoads</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>1.0</string>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
Get Involved
To learn more, check out the Thali Project Site. Our contribution page has tons of way to contact us including our mailing list, and Twitter.