Swift in Android Apps

Posted on

The inability to share code between the iOS and Android ecosystems is a known issue and as it’s unlikely Java will be making an appearance on iOS any time soon (even if Kotlin could!), the focus has to be whether Swift can be used in Android apps. Android also has lots of issues with malware and spyware that can’t be solved easily.

Shortly after Swift was open-sourced, Zhuowei Zhang sent an email to the swift-dev mailing list, introducing a fork of Swift that was able to produce Android binaries. Brian Gesiak worked this into a pull request which was merged in Feb 2016. Zhuowei also published a proof of concept applicationthe best part of which was that it used the Swift Package Manager for the build so you could bring in other/Open Source files via git like a conventional project. It wasn’t long before Geordie J announced they had been able to publish an app containing Swift to Google Play using this one simple trick. Ports of Dispatch and Foundation followed in short order.

With Swift 4 on the horizon momentum has picked up again using Gonzalo Larralde’s swifty robot environment that can be used to build a swift toolchain for Android in a Docker container. This, and a couple of recent PRsmeans a viable environment exists that opens the possibility that model, business logic and network code can be shared between Android and iOS when it is written in Swift.

Beta Swift Android Toolchain

Bringing these contributions together a Toolchain has been prepared for Android which you can download from this link.

The toolchain will allow you develop Apps on macOS or Ubuntu Linux 16.04 provided you run the script swift-install/ afater extracting the archive. This links from your existing toolchain into the release tree and installs a basic gradle plugin to hook into the build process. To add a swift build to your Android studio project, add a classpath dependency for net.zhuoweizhang:swiftandroid:1.0.0 to it’s build.gradle and apply it.

These ideas are all brought together in a simple example app. Some generic JNI supprt code for the Swift side is taken from the java_swift project which is included in the project’s Package.swift for cloning. A feature of the toolchain’s gradle plugin is that it includes the code generator genswift.javaand, if the package name of your bindings file contains the path “swiftbindings”, all JNI code generation will be performed automatically as part of the build process when required.

In the examples, the app binding sources are contained in the directory:

The generated Swift with the JNI required will be placed in:

Some supporting Java proxy classes for messaging from Java to Swift will also be generated in:

The result is an application & build process something like the following:

The toolchain could be described at being at a fairly advanced stage of Beta with a view to a release when Swift 4 firms up. If you have any problems with the toolchain, please file an issue with the repo set up for this purpose, or you can contact the authors by email. Announcements of major releases will be made on twitter @Injection4Xcode.

Code Generator —

The only way for native apps to communicate to Java, the Java Native Interface, is renowned for requiring acres of inadequately checked boilerplate code. To avoid this, a code generator script has been written which takes this off the developer’s hands and introduces strong type safety. The script takes as input a set of Java sources (the “bindings”) specifying the interfaces and types that bind the two parts of an application together. Using this generated code, primitives, objects, collections can be passed from Java to Swift and messaged. Conversely, Swift objects and structs and collections can be passed back to Java if they conform to one of the protocols declared in the bindings and the protocol name ends in “Listener”.

The following type mappings are available from the generator as arguments or return values out of the box:

Java TypeSwift Typeboolean, byte, char, short, int, long, float, double, String<−>Bool, Int8, UInt16, Int16, Int, Int64, Float, Double, Stringboolean[], byte[], char[], short[], int[], long[], float[], double[], String[]<->[Bool], [Int8], [UInt16], [Int16], [Int32], [Int64], [Float], [Double], [String]boolean[][], byte[][], char[][], short[][], int[][], long[][], float[][], double[][], String[][]<->[[Bool]], [[Int8]], [[UInt16]], [[Int16]], [[Int32]], [[Int64]], [[Float]], [[Double]], [[String]]Where the enum, class of object or interface are declared in the bindings file:enum, enum[], enum[][]<->enum, [enum], [[enum]]object, object[], object[][]<->object, [object], [[object]]interface, interface[], interface[][]<->protocol, [protocol], [[protocol]]Map types require a static valueClass()method declared on a concrete typeMap<String,String>, Map<String,[String]]><->[String:String], [String:[String]]Map<String,object>, Map<String,[object]]><->[String:object], [String:[object]]Map<String,protocol>, Map<String,[protocol]]><->[String:protocol], [String:[protocol]]

By convention, all non-primitive arguments are optional and the return type for functions returning a non-primitive is an implicitly unwrapped optional. A function that throws can throw an Exception object from Swift back to Java and vice versa.

A typical bindings file linking the two sides of the two example applications looks like this:

package com.johnholdsworth.swiftbindings;

import com.johnholdsworth.swiftbindings.SwiftHelloTypes.TextListener;

import com.johnholdsworth.swiftbindings.SwiftHelloTypes.ListenerMap;

import com.johnholdsworth.swiftbindings.SwiftHelloTypes.ListenerMapList;

public interface SwiftHelloBinding {

// Messages from JavaActivity to Swift

public interface Listener {

public void setCacheDir( String cacheDir );

public void processNumber( double number );

public void processText( String text );

public void processedMap( ListenerMap map );

public void processedMapList( ListenerMapList map );

public void processStringMap( StringMap map );

public void processStringMapList( StringMapList map );

public double throwException() throws Exception;

public SwiftHelloTest.TestListener testResponder( int loopback );


// Messages from Swift back to Activity

public interface Responder {

public void processedNumber( double number );

public void processedText( String text );

public void processedTextListener( TextListener text );

public void processedTextListenerArray( TextListener text[] );

public void processedTextListener2dArray( TextListener text[][] );

public void processMap( ListenerMap map );

public void processMapList( ListenerMapList map );

public void processedStringMap( StringMap map );

public void processedStringMapList( StringMapList map );

public double throwException() throws Exception;

public String[] debug( String msg );

public SwiftHelloTest.TestListener testResponder( int loopback );



The types can be separated out into their own file:

// Shared types/interfaces between Java and Swift

package com.johnholdsworth.swiftbindings;

import java.util.HashMap;

public interface SwiftHelloTypes {

// An example of publishing an object to Java.

// Add the associated protocol to an class and

// objects can be passed to a responder message.

public interface TextListener {

public String getText();


// These are required because of type erasure in Java jars

public static class ListenerMap extends HashMap<String,TextListener> {

public static Class<?> valueClass() {

return TextListener.class;



public static class ListenerMapList extends HashMap<String,TextListener[]> {

public static Class<?> valueClass() {

return (new TextListener [] {}).getClass();



public static class StringMap extends HashMap<String,String> {

public static Class<?> valueClass() {

return String.class;


public StringMap() {




public StringMap(Map map) {




public static class StringMapList extends HashMap<String,String[]> {

public static Class<?> valueClass() {

return (new String [] {}).getClass();


public StringMapList() {




public StringMapList(Map map) {





Finally, to tie the two sides of the application together there is one JNI entry point you need to provide in Swift to bootstrap the link between the two languages. This called as a native method from Java when the application starts.

// link back to Java side of Application

var responder: SwiftHelloBinding_ResponderForward!

// one-off call to bind the Java and Swift sections of app


public func bind_samples( __env: UnsafeMutablePointer<JNIEnv?>, __this: jobject?, __self: jobject? )-> jobject? {

// This Swift instance forwards to Java through JNI

responder = SwiftHelloBinding_ResponderForward( javaObject: __self )

// This Swift instance receives native calls from Java

var locals = [jobject]()

return SwiftListenerImpl().localJavaObject( &locals )


From here it’s a case of writing Java or Kotlin code against the binding interfaces as you would normally and Swift code against the generated types which will have a name like SwiftHelloTypes_TextListener. You can see how it looks from the Android side in Java & Kotlin. The corresponding Swift implementation can be viewed here.…


Digital Nomad Communications

Posted on

One of our many concerns in planning for digital nomadism was figuring out how we could stay in touch (beyond email) with family, friends, and work back in the US without breaking the bank. It turned out the solutions were pretty easy and cheap. Jason Lengstorf of Untethered had suggestions, and in addition I googled to see what others were doing.

In the end, here’s what I did:

For business calls/messages:

My company is using Skype for Business, which ties to Outlook. I have the Skype for Business app on my phone and laptop. We can create meetings in Outlook and choose “Skype Meeting,” which will include a link to join the meeting as a conference call in both the Outlook event and in the Skype application. So when the time comes you just click “Join” to connect to the conference call.

I call in to our daily “10@10” call and our weekly project management and strategy meetings with no problem. My boss and I use Skype for Business to have a weekly call to catch up also.

I have so few calls with people outside my organization. I just call them through regular Skype (see below).

The power does go out with some regularity in Nicaragua. At the coworking space, after a moment, generators will kick on. But I do have the risk of a call being interrupted if the power goes down (and thus disconnects the wifi).

For other calls/texts to/from the US:

1. Ported my mobile phone number to Google Voice. I have had the same number since 1999 (first as a landline and then as a mobile number) and didn’t want to lose or change it. So I transferred it from AT&T (my mobile carrier) to Google Voice. In GV it became a forwarding number, no longer tied to any service. GV forwards it to whatever number I want. So, folks could continue calling and texting me on that number. I just had to decide where GV should forward it.

2. Signed up for a Skype number and International Skype Plan. I already had a Skype handle for computer-to-computer Skype calls (which I can still do, anywhere in the world for no charge). But for GV to forward calls somewhere, I needed to give them a phone number. I paid an annual fee for a Skype number, and it was 50% off because I also paid for a calling plan. The plan literature said international calls are generally $0.20/min but so far in checking my account online, none of the calls I’ve made or received over the first two months has cost anything per minute (they all appear to be covered under the $13.99 monthly fee so far).

3. Told GV to forward calls to the Skype number. People call my same number and GV forwards to the Skype number. If I don’t answer, it goes back to GV and people can leave voicemail there. Texts also just go to the GV number. I can send & receive texts in the GV app on my phone or via their web interface, and listen to voicemail as well in either app or web. GV also does a decent job transcribing voicemails so I can read them in the interface (usually well enough to get the gist even though the transcription isn’t perfect).

If/when I return to the states permanently and want a phone plan, I can let the company assign me whatever number, and change GV to forward to that new number. So my number can always remain the same as far as my friends and family can tell.

For local calls, texts, and data:

It’s handy to have a local number for making reservations, and I wanted local data for using maps and any other things I might want to use my smartphone for when away from the trusted WiFi of the coworking space or our lodgings. It’s less important to have a local number for texts (based on just Nicaragua so far) because Nicas mostly use What’s App for messages. (But we might find being able to get local texts is useful in some countries; and anyway, texting capacity comes with local calling plans).

For local calls/text/data, I bought a local pay-as-you-go SIM card on arrival in Nicaragua and replaced my existing SIM card (for my AT&T plan, which was defunct since I moved to GV/Skype — I dropped my AT&T plan). It’s inexpensive to top up minutes/data once a week or so as I use up what I paid for. I drop into pretty much any bodega, pulperia, internet café, etc. and they recharge my card for me in about 30 seconds.

The deal I’ve been getting in Nicaragua is 110 Córdobas for 7 days of service (500 MB data, 20 minutes of calls, 20 SMS). So that’s about $3.50/week, $15.75/mo. Add to that my $13.99/mo Skype plan and I am paying about $30/mo for phone/text/data. (For reference, my AT&T plan was about $97, including unlimited data, 500 minutes of calls and 1000 texts. I barely used any minutes and few texts.)

So, while it was a little juggling to do the Google Voice thing, it wasn’t hard and I was up and running in a few days. Communication with locals as well as people back home has not been a problem!…


How to install WhatsApp on an iPad? (without iPhone method)

Posted on

After trying around a lot, I discovered this easy method of installing WhatsApp on an iPad (or iPod touch). You don’t need an iPhone or any configuration utilities. Just a jailbroken device with Installous.

If you face errors finding WhatsApp within Installous, go to Settings (within Installous) and disable the “Only Show iPad Apps” option. Also, try clearing the Cache or rebooting.

I’ve personally tried it out a few days ago and it worked exactly as mentioned. You can also read the text version of the tutorial.…


How to Update Your Antivirus Software

Posted on
How to Update Your Antivirus Software

Some companies think they are protected from viruses, just because they have installed the virus protection program.This may occur frequently.

For complete protection against virus threats from your computer, there are few steps:

Get a good virus protection program (The most used are Norton and McAfee) or get a Fix Me Stick.

1 – Install the software, do it and keep it running.

2 – Upgrade the software on your anti-virus on a regular basis.

To have a good virus protection program, they must follow next steps.

First step: Get virus protection programs

Buy a good virus protection program is simple. You can do it from many electronics or computer store. Today, there are also many bookstores and shops selling software. Another possibility is that a program download anti-virus directly from the Internet.

Second step: Installation

When you install your anti-virus program, you have several options to choose from. Prepare the program to review all files automatically. Once your program is installed, simply start the program and find areas where you can verify that the program is operated to examine automatically.

Third step: update regularly

Most people will be left after the first two steps. However, should the third step is essential. You must update your virus protection program on a regular basis to keep up to date. Most virus programs consist of two main aspects: the scanner (exam), which investigates conduct of heuristic-type virus, and a database of model virus, sometimes called names virus files identifying specific virus, known. The database is the part that needs to be updated. Each month they discovered much new viruses.The companies that manufacture anti-virus software incorporating processes for detection of new viruses as rapidly as they are discovered. However, the software on your computer will not remove the new virus until you do not update your anti-virus.

Use the Automatic Update

Most new versions of their anti-virus programs have a range of automatic updating. To use this range, simply log onto the Internet, start the anti-virus program and click the button Update (Update). The update process is automatic. But not always the update is done automatically.

Installing Updates

Many anti-virus programs offer free upgrades, but some charge a minimal fee to take a more recent version, which protects completely the vast amount of viruses that appear every day. Consider the investment being made in the anti-virus software as the cost of insurance. It is a safe with which it must at present.

After you have updated their virus protection program, you’ll want to examine your hard disk to make sure it has not been infected by any new virus, since last update. Remember that many viruses are activated by a certain date. They can be very long in the system of your computer without doing any damage.

If the anti-virus find a virus, will warn you first and then remove the virus. This is a quick and easy process that requires a minimum knowledge or user intervention. In many cases, the agenda for the protection of the virus will remove the virus and repair your files without any loss of data. It is better to be safe rather than suffer for the loss of some important file, for not having updated in time.…


How To: Mount your ssh connection as a local folder on Fedora Core 6

Posted on

Do you have an ssh login to a server? How would you like to access that on your Linux desktop as if it were local? As it turns out, this isn’t hard to do, thanks to the power of FUSE (Filesystem in Userspace). Here’s the quick and dirty way to set this up on Fedora Core 6.

Install FUSE

First, you need FUSE, as well as the sshfs module. To do so, open up a command prompt, and do the following:

su -
yum install fuse
yum install fuse-sshfs
usermod -G fuse youraccount

Replace youraccount in the above with your user account. The last line adds you to the group fuse, although if you are in other groups, it’ll remove you from them. You’d want to specify all additional groups you’d want to be in, e.g. usermod -G fuse group1 group2 youraccount. If you’re logged in under your account, then you should log out and back in, so the group change takes effect.

Mount a Folder

Let’s say you want to create a mount point on your desktop so you can browse it. Do the following:

cd ~/Desktop
mkdir remote_folder
sshfs yourserver.someplace.not:/home/yourusername remote_folder

Replace yourserver.someplace.not with the ssh server you want to mount. Replace /home/yourusername with the remote folder you want to mount. If your local username differs from your remote username, you’ll have to specify it, e.g. sshfs remoteusername@yourserver.someplace.not:/home/yourremoteusername remote_folder

Once you do this, it should be all set — you can browse it from the desktop, and browse it from the command line, as if it were local.

Unmount a Folder

Unmounting is pretty simple; use fusermount -u mountpoint. For instance, in the above, you mounted an ssh share to ~/Desktop/remote_folder. To unmount this, just issue:

fusermount -u ~/Desktop/remote_folder

That’s all there is to it!…


Focus Stealing In Ubuntu Beryl

Posted on

Are you running Beryl on Ubuntu? Do you have the problem where dialog boxes or new windows open under your existing window? This is most noticeable when web browsing, and coming across password-protected pages. I’ve been annoyed by this bug for about a month now.

It turns out, this is not a bug, it’s a feature. Beryl has a setting called “Focus Stealing Prevention”, designed to keep windows from stealing your focus. This is great if you really need to concentrate; it’s annoying if you need to find the password dialog box before proceeding.

To fix, open up the Beryl Settings Manager, and click on General Options. In here on the Main tab, you should find an option for “Level of Focus Stealing Prevention”. This is probably set to “Extreme”. Switch this to normal and voila — your windows should behave normally again.…


Lenovo X41 Recovery CDs not booting? Check the partitions

Posted on

I have a Lenovo X41 Tablet PC that I had installed Ubuntu onto. I recently decided to re-install the original Windows software, so I ordered the CDs from Lenovo and broke out an external CD drive. However, when I put in the Rescue and Recovery CD and booted the machine, I ended up with a blank black screen and nothing else. What gives? I updated the BIOS and the embedded controller firmwares, but to no avail. The computer would boot up the CD, a brief message about examining the setup would fly by, then a blank screen. I figured this was a problem with the recovery CDs, because my Ubuntu live CD booted right up.

As it turns out, Lenovo recovery CDs are very picky about their hard drive setup. They need to copy files to disk for a variety of tasks, so if you’re using up all the partitions, then the CDs will stop booting, but give you no other errors.

I had previously installed Linux on the machine, so my partition tables were in a state the machine didn’t really understand. What I needed to do was trash the existing partitions, and flush out the boot record.

Easy enough — I fired up the Ubuntu live CD, and launched the partition editor in System -> Administration. I had to turn off the swap space, by right-clicking on it in the partition editor, and selecting “swapoff”. By default, Ubuntu live CDs will scan your drives for partitions marked as swap space, and use it, so you have to turn off this usage to delete the partitions. I ran through and deleted all the partitions, and applied the changes.

I next had to clear out the master boot record, but I could do that right from the live CD. After doing that, I rebooted with the Lenovo Rescue and Recovery CD and said a little prayer.

Once I had done these steps, the recovery CD started right up. I’m surprised Lenovo doesn’t give more details on this in their support knowledge base.…


Firefox, Emacs, and Mac OS X

Posted on

On Linux and Windows, I use an extension called It’s All
Text to add an “edit” button to text areas. Hitting this will
launch the contents of the text area in my editor of choice — emacs.
(You can pick any editor you like.)

However, on Mac, it’s not really straightforward, due to the way they
handle applications. The comments in this
post pointed me in the right direction for how to set this up.

The default proportional font in aquamacs bugs me, so I fix that by
launching it with a textarea and going to Options -> Appearance
-> Font For Text-Mode and setting it to Andale Mono. I also turn
off Soft Word Wrap and Auto Word Wrap In Text Modes under options,
because I’m used to emacs’s old unfriendly behavior.


Gutsy Gibbon + Radeon Mobility X1400

Posted on

Compiz Fusion on a Radeon Mobility X1400 graphics card? Hell yeah!

Oh, driver hell. Proprietary drivers are the bane of Linux’s existence, as any Linux user with a current ATI graphics card can tell you. I have a Lenovo Z61m on which I’d like to install Ubuntu Gutsy Gibbon, but good luck — the ATI Radeon Mobility X1400 will wreak havoc on your installation procedure. This is not new; Feisty Fawn had the same problem. Fortunately, you can in fact work around it.

Installing From the Live CD

First, there’s getting the live CD to work. You can download the alternate install CD and work from text mode, but I’d much rather use the regular live CD. Fortunately, you can! Boot up the live CD, and it’ll eventually die at some point, because the X server can’t launch properly. Hit Cntrl + Alt + F2 to jump to a virtual console. Type clear to clear the screen, then type the following:

sudo apt-get update
sudo apt-get install xorg-driver-fglrx
sudo depmod -a
sudo aticonfig --initial
sudo aticonfig --overlay-type=Xv

You’ll obviously need a working Internet connection to make this work. Congratulations, you can now use the live CD! Run the installer as per normal.

Special note for Lenovo users: Do not delete the FAT32 service partition! You can use this to restore your Windows partition or run other diagnostics. I found it worked well to resize the existing Windows partition and dual boot.

After installation, you’ll reboot your system and — surprise! It doesn’t work. It’ll die at loading the X server again. Hit Cntrl + Alt + F2, and enter the following:

sudo apt-get update
sudo apt-get install xorg-driver-fglrx
sudo apt-get install xgl
sudo apt-get install xserver-xorg-video-radeonhd
sudo depmod -a
sudo aticonfig --initial
sudo aticonfig --overlay-type=Xv

This is slightly different than before. Why? Well, no doubt you want to use those fancy Compiz Fusion effects, right? You didn’t need them to do the installation, but installation is done now. You’ll need to get the right drivers, as well as install xgl. Once you’ve done that, you might also need to edit /etc/X11/xorg.conf to change Option "Composite" "0" to Option "Composite" "1". After that, you should be able to enable Visual Effects through System->Preferences->Appearance, Visual Effects tab.