Titanium

Enhancing Titanium: How to use Images that require authentication


Note: This post was originally published on Medium. Rene Pot is an Appcelerator Titan, long time member of the Titanium community, and runs the Slack Titanium Channel @Ti_Slack. For more, you can follow him on Medium and Twitter.

It is really easy to include images in your app. Just add an ImageView to your View and add the URL and you’re done.


<ImageView id="mainImage" image="https://example.com/image.png" />

While you’re developing the app, and the backend of your app evolves the need arises to secure the system. Images are no longer public and they need to be fetched using oAuth tokens. So what do you, rewrite the entire app to be able to fetch images?

In fact, you can change it easily with minimal effort and hardly any impact on your code. But it will require you to not use the ListView component, as ListViews have no extend support.

Extending Alloy

The answer to this problem is in Alloy Extending. There is a property you can use in your Alloy View called module. Within your Views, this is the only change you need to do.


<ImageView module="authImage" id="mainImage"
                   image="https://example.com/image.png" />

As you can see, I added module="authImage" . What this does is it looks for a commonjs/module/widget inside your app. Under the hood it behaves like require('authImage'). In fact, because I use ImageView here, the exact code this translates to is: require('authImage').createImageView(args).

As you can see, this gives a great opportunity to add logic to ImageViews. I will guide you through the creation of the module, or in this case a commonjs file from the lib folder.

Note: This solution is only possible with Alloy

Creating authImage lib

As discussed above, Alloy is looking for a createImageView function inside the authImage lib. So the basic thing the lib needs to do is have a function called createImageView and that function should return an ImageView. Your file (/app/lib/authImage.js) should look something like this:


function createImageView(args){
    var igvm = Ti.UI.createImageView(args);
    return igvm;
}
module.exports = {
    createImageView: createImageView
};

This basic example basically overrides your createImageView method and makes it possible for you to extend. Every property you set in tss or xml file regarding the ImageView will be inside the args variable. For instance, the url to the image.

From now, you will need to intercept the image and insert it later. For this you need to create a function inside the lib that initiates an XHR call with the token as a requestheader. You can probably hook it up to the flow you probably already have internally, or create a small http call inside the lib file (I recommend the first).

As the code immediately becomes a lot longer, I’ve open sourced my code that does an API call and stores the file in the temp directory in your app. You can see the related code here: https://github.com/Topener/authenticatedImageView/blob/master/lib/authImage.js

The entire repository is dedicated to downloading images and storing them. Just have a proper look at the code in this repository and you can see how easy it is to download images like this.

Extending it even further

You’ve now touched the first base of extending Alloy elements using the module tag. It can be quite powerful. For example, you could resize images to square inside your lib file, or rotate them, or change colors, or do more awesome things. You could even add a button on top of the ImageView with an example like this:


function createImageView(args){
    var wrapperView = Ti.UI.createView({height: Ti.UI.SIZE, width: Ti.UI.SIZE});
    wrapperView.add(Ti.UI.createImageView(args));
    wrapperView.add(Ti.UI.createButton({width: 50, height: 50, bottom: 10, right: 10, title: '?'}));
    return wrapperView;
}

You get the point, everything is possible. I’m curious what you come up with.

Meetup

This blogpost originates from a TitaniumNL meetup where I discussed this exact topic.