Handling binary responses in native iOS using Java adapters

Starting with MobileFirst Platform 7.0, you can send and receive arbitrary data to your client's device using Java Adapters.

Overview

In this example, I will show a native iOS (Swift) application that can convert a string to a QR code. The user will input a string (for example a URL), submit it to the Java Adapter, which will in turn send an image representing the QR code. The iOS application will handle the binary data and display the image.

Adapter code

I've created a MobileFirst project called BinaryResponse. In it I've added a Java Adapter called QR.

To make the QR generation easier, I am using the ZXing library. I've copied core-3.2.0.jar and javase-3.2.0.jar into the lib folder of my adapter.

I left QRApplication.java as-is and wrote my code in QRResource.java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Path("/")
public class QRResource {
	//Define logger (Standard java.util.Logger)
	static Logger logger = Logger.getLogger(QRResource.class.getName());
    //Define the server api to be able to perform server operations
    WLServerAPI api = WLServerAPIProvider.getWLServerAPI();
	@GET
	@Path("/{itemId}")
	@Produces("image/png")
	public Response getQR(@PathParam(value="itemId") String id) throws WriterException, IOException{
		QRCodeWriter writter = new QRCodeWriter();
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		BitMatrix bitMatrix = writter.encode(id, BarcodeFormat.QR_CODE, 200, 200);
		MatrixToImageWriter.writeToStream(bitMatrix, "png", stream);
		return Response.ok(stream.toByteArray(), "image/png").build();
	}
}

I used @Path("/") at line 1 to define that the URL path for my resource should just be /adapters/adapterName. The adapter resource file contains only one method, getQR, which can be accessed via HTTP GET using the path @Path("/{itemId}") at line 11, where itemId is the string provided by the user.

The method uses @Produces("image/png") and automatically adds the image/png Content-Type in the response.

The implementation details of this method are out of scope and can be understood from the ZXing documentation. All I did was use QRCodeWriter to encode the string to a 200 by 200 bar code. The resulting stream is returned in the response.

Xcode Project

I've created a new Xcode (Swift) Project named BinaryResponse and configured it to use MobileFirst Platform.

The storyboard simply shows a text field to enter the string, a button to trigger the request and a 200px/200px UIImageView to display the generated QRCode.

1
2
3
4
5
6
7
8
    @IBAction func generate(sender: UIButton) {
        var escapedString = self.code.text.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
        if(escapedString != nil){
            let request = WLResourceRequest(URL: NSURL(string: "/adapters/QR/" + escapedString!), method: WLHttpMethodGet)
            var delegate = BinaryDelegate(imageView: self.imageView)
            request.sendWithDelegate(delegate)
        }
    }

Clicking on the Generate button creates a WLResourceRequest that points to the adapter URL, with the user provided string appended.

I used sendWithDelegate and created a new class called BinaryDelegate to handle the response.

BinaryDelegate implements NSURLConnectionDataDelegate.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class BinaryDelegate: NSObject, NSURLConnectionDataDelegate {
    var responseData = NSMutableData()
    var imageView: UIImageView
    init(imageView : UIImageView){
        self.imageView = imageView
    }
    func connection(connection: NSURLConnection,
        didReceiveData data: NSData){
            NSLog("In didReceiveData");
            NSLog("%@", data)
            responseData.appendData(data)
    }
    func connectionDidFinishLoading(connection: NSURLConnection){
        NSLog("In connectionDidFinishLoading")
        self.imageView.image = UIImage(data: self.responseData)
    }
    func connection(connection: NSURLConnection, willSendRequest request: NSURLRequest, redirectResponse response: NSURLResponse?) -> NSURLRequest? {
        NSLog("in willSendRequest")
        return request;
    }
}

As data comes back from the request, I store it in a temporary NSMutableData object. On connectionDidFinishLoading I used the saved data to set the image in the user interface.

willSendRequest needs to be implemented and simply return the request, or the request will not be sent.

Sample

You can find the code for this example on GitHub.

For best results, make sure you use MobileFirst with the latest iFix available by checking for updates in Eclipse, or IBM Fix Central if you have installed a Studio version from there.

missing_alt
Last modified on May 18, 2016
Share this post: