The best part of the improved backwards compatibility achieved by Apple & Google this year is that we got to spend more time on new features we think you’ll love and give you even more reasons to smile!

display

file

icons

launchimage

Update to "version": "2.13"

media

Update to "version": "2.5"

notification

Update to "version": "2.8"

parse

Update to "version": "2.17"

platform

Update to "version": "2.3"

request

Update to "version": "2.10"

While every effort has been made to ensure backwards compatibility it is possible that you may run into some subtle differences in behaviour. If you do run into any issues please get hold of us on support@trigger.io!

tabbar

Update to "version": "2.6"

tabs

Update to "version": "2.18"

topbar

Update to "version": "2.13"

tribr_multi_image_select

Update to "version": "1.4"

Optional: configure content inset behavior on the iPhone-X

To accommodate the rounded corners and “notch” of the iPhone-X Apple have introduced the idea of so-called “safe areas”.

By default Forge apps will limit the accessible portion of your app’s web view to the following area defined by the notch and corners:

To give your app full access to the full extent of the webview you will need set the content insets as follows:

1

2

3

4

5

6

"core":{

"ios":{

"adjust_content_insets":"never"

}

}

Optional: enable httpd module

Historically Forge apps have served their content directly from the device filesystem using the file:// scheme.

Over time this has created more and more problems as Google or Apple continue to introduce restrictions targeting the http:// and https:// schemes without considering their impact on other RFC 1630 URL types.

With the latest version of Android “Oreo” 8.0 (API level 26) we’ve identified the following features that are directly impacted by this:

WebSockets

IndexedDB

If your app uses one or more of these features you will need to enable the httpd module for your app.

Optional: enable experimental support for iOS WKWebView

You can enable experimental WKWebView support for your app by editing your app’s src/config.json file:

1

2

3

4

5

6

"core":{

"ios":{

"webview":"WKWebView"

}

},

If your app makes use of XHR requests (e.g. for Ajax or dynamic script includes) you will also need to add the httpd module as Apple have restricted WKWebView to only allow XHR requests from CORS-configured endpoints. See the Optional: enable httpd module section above for instructions.

The WKWebView features required to integrate fully with Forge are only available on iOS 11 devices so the default behavior is to automatically fall back to UIWebView on earlier iOS devices.

You can force WKWebView to be used on older iOS devices as well by adding the following flags configuration:

1

2

3

4

"flags":{

"ios_force_wkwebview":true

}

Please note that some Forge features can not be supported in this configuration.

Amongst other issues, you will find that you are unable to embed content from your device’s asset stores in your app.

Optional: enable experimental support for JavaScript ES6 Promises

Open your app’s src/config.json file and add a new top-level section as follows:

1

2

3

4

5

6

7

8

9

{

...

"platform_version":"v2.6.3",

"flags":{

"promises":true

},

...

}

Now you can finally replace this:

1

2

3

4

5

6

7

8

9

10

forge.file.getLocal("index.html",function(file){

forge.file.string(file,function(content){

forge.logging.log("Read "+content.length+" characters from file.");

},function(error){

// handle forge.file.string() error

});

},function(error){

// handle forge.file.getLocal() error

});

…with this:

1

2

3

4

5

6

7

8

forge.file.getLocal("index.html").then(function(file){

returnforge.file.string(file);

}).then(function(content){

forge.logging.log("Read "+content.length+" characters from file.");

}).catch(function(error){

forge.logging.error("Oh no!");

});

Yay!😄

We’ve bundled a Polyfill for backwards-compatibility so this should also work on older Android and iOS versions.

Problems?

New Android and iOS releases are always a little stressful. Please don’t hesitate to join us on the Forge 2.6 Community Forum Topic if you have any questions around the update process or run into any difficulties!

Overview

Starting on Friday, the 14th of October 2016, we experienced a succession of increasingly severe network failures which culminated in a near total service outage by 01h30 UTC on Tuesday the 18th.

As a result many of our customers were unable to access the Trigger.IO website, Toolkit or Build servers during this time.

The failure first became visible on Friday afternoon when we received a support email from a customer who was unable to perform builds. At the time our monitoring system showed no problems and the customer replied to my initial queries that the problem had resolved itself.

I was puzzled but ended up writing the incident off as a brief routing problem on the wider Internet and did not think about it again until the emails started flooding in late Monday night.

At this point in time our monitoring system was still reporting 100% uptime and I had no difficulty accessing any of our infrastructure from the office.

This was about to change.

At 01h30 UTC I observed a rapid rise in the failover graph followed by most of the individual server monitors turning red.

By 3h00 UTC we discovered that a network router responsible for one of our server instances had failed and we took that region offline.

Recovery was almost immediate but we still had no clear picture of what had happened or the full extent of downtime experienced by our customers.

Extent

We were contacted by 12 different customers who experienced an outage during this period.

The shortest period reported was 1 hour starting around 02h00 UTC.

The longest period reported is an estimate of 3-4 days starting late Saturday or early Sunday.

5 of the affected customers are based in California, USA.

3 of the affected customers are baed in other parts of the USA.

1 of the affected customers is based in Germany.

3 of the affected customers are based in the United Kingdom.

What Happened?

1) For an unknown period of time a network router in the West Coast, USA data center region has been experiencing intermittent hardware failures.

2) Specifically, the router’s BGP table was experiencing corruption which prevented it from routing traffic originating from some regions of the Internet.

3) Around Friday the router’s rate of failure started to increase and by 01h30 UTC on Tuesday morning it was going through a rapid cycle of failures and recoveries.

4) This caused our failover system to start receiving conflicting information about server availability resulting in a cascade of increasingly rapid switchovers of traffic between server regions and ultimately leading to a global service outage.

5) Because our monitoring system was not on a network affected by the router in question we were only able to detect the failure by the time we experienced a global outage.

6) Because our monitoring system checked for host uptime rather than individual API endpoint availability we were unable to monitor metrics that could have helped us identify routing failures earlier.

A big thank you to all the Trigger.IO customers who provided information that helped us to reconstruct what happened.

Remediation

The following steps have been taken to ensure this does not happen again:

Trigger.io Forge v2.5 and iOS 10 Migration Guide

The iOS 10 launch is upon us and it’s time to release the next major Forge platform update.

Every year Apple blesses us with some changes and, being a conscientious cross-platform framework provider, we do our best to minimize the impact on your team.

The shift is usually transparent but this year a few fundamentals have changed and will require a bit of work to get your app ready for iOS 10:

iOS 10 now requires app permission dialogs to display a short usage description explaining why it requires access to device features such as the camera, contacts and calendar.

iOS LaunchImages are no longer organized according to device screen resolution. Instead, they are now assigned to size classes. This is good news as it means that the number of separate image files required for iOS have gone down from 13 to only 4.

Apple are getting serious about App Transport Security (ATS) and, as of 01 January 2017, its use will be mandatory for all App Store submissions. If you are using the request module and your backend infrastructure is still running HTTP or not configured to modern SSL standards your app will be affected.

Let’s take a quick look at each of these and the steps you will need to take to update your app for Forge Platform v2.5.x.

Module upgrades for iOS 10

If you are using any of the following modules you will need to make sure they are on the latest version:

Module

Min Version

Notes

calendar

2.8

Requires a usage_description entry

contact

2.10

Requires a usage_description entry

file

2.12

Requires a usage_description entry

tribr_multi_image_select

1.3

Requires a usage_description entry

launchimage

2.10

Requires new launch images

request

2.8

Requires App Transport Security (ATS) configuration

icons

2.7

Requires an iPad Pro icon (167x167px)

barcode

2.5

No app changes required

Add usage descriptions to your module configuration

iOS 10 requires app permission dialogs to display a short usage description explaining why it requires access to device features such as the camera, contacts and calendar:

To configure the usage description for each of the modules you can fill in the usage_description field in the config section of src/config.json or the module configuration page in the Toolkit.

For example, to configure the calendar module you can either edit your app’s src/config.json file directly:

1

2

3

4

5

6

7

8

9

"modules":{

"calendar":{

"version":"2.8",

"config":{

"usage_description":"We would very much like to surprise you on your birthday."

}

},

...

…or you can access the configuration through the Toolkit:

Please note that trying to your app on iOS 10 without a usage description will result in your app exiting immediately when its API methods are invoked!

iOS LaunchImage Size Classes

Apple introduced the concept of adaptive layout in iOS 8 already but, as hybrid devs, we haven’t really been affected as it only applied to native user interfaces.

With the release of iOS 10 however Apple are now requiring the use of Storyboards for App launch screens which means that the old system of having a different launch image for each device pixel resolution falls away.

Instead, there are now only four launch images, one for each Size Class defined in Apple’s adaptive layout framework.

When you App launches, iOS will select the corresponding launch image for the Size Class corresponding to the type of device running the app and its orientation.

Step 1: Upgrade the launchimage module to v2.10

Please make a note of the settings for your Android launchimage configuration before updating!

With the breaking changes for iOS we took the opportunity to do a long-needed re-organization of the module configuration schema and give the properties for Android their own section.

Step 2: Generate new launch images for each size class

The concept of size classes can be somewhat confusing at first but we can get away with only needing to remember that there are four size classes and they are applied as follows:

Size Class

Device

Landscape

Portrait

Image Size

width: Compact height: Compact

iPhone

x

1334 x 750px

width: Compact height: Regular

iPhone, iPhone Plus

x

1080 x 1920px

width: Regular height: Compact

iPhone Plus

x

1920 x 1080px

width: Regular height: Regular

iPad

x

x

2732 x 2048px

Step 3: Configure the launchimage module

Finally, to configure the launchimage module you can either use the Toolkit or simply edit your app’s src/config.json file to look something like:

App Transport Security (ATS)

In a nutshell, App Transport Security (ATS) is a requirement that all iOS App communication with remote servers via the request module use the HTTPS protocol and conform to the following minimum requirements:

Encrypted using AES-128 or better.

SHA-2 for certificates with either a 2048 bit or greater RSA key, or a 256 bit or greater Elliptic-Curve (ECC) key.

Tansport Layer Security (TLS) protocol must be v1.2 or greater.

All connection ciphers must be using forward secrecy.

This only applies to communication via the request module. Network access from the iOS WebView is still exempt from ATS.

Step 1: Upgrade the request module to v2.8

If you are already using HTTPS conforming to Apple’s security requirements for all communication with your backend infrastructure this is all you’ll have to do.

If you are still relying on HTTP for communication with backend infrastructure you will want to read the next steps!

Step 2: Disable ATS for development

Unless you are ready to roll-out SSL across your backend by this afternoon you’ll probably want a way to disable ATS during development.

Please be aware that submitting any iOS App built with this setting enabled to the App Store after 1 January 2017 will result in immediate rejection.

To disable ATS you can either edit your app’s src/config.json file:

1

2

3

4

5

6

7

8

9

"modules":{

"request":{

"version":"2.8",

"config":{

"disable_ats":true

}

},

...

…or modify the configuration via the Toolkit:

Step 3: Make a plan to upgrade your backend infrastructure to HTTPS

The most common obstacle to upgrading server infrastructure is that the cost & difficulty of getting set up with SSL certificates can be a major barrier for projects.

If this is the case for your project we’d like to recommend you check out Let’s Encrypt. Let’s Encrypt is a free, automated Certificate Authority that operates with support from a large number of sponsors such as Mozilla, the EFF, Chrome and Cisco.

The next most common obstacle to upgrading to SSL is that sometimes we rely on servers that are not under our direct control.

For these cases Apple have communicated that they will allow some temporary exceptions to smooth the transition, but the rules moving forward are strict:

Most exceptions will need to be justified to Apple. This will likely lead to delays during the approval process and may end with your app being rejected.

NSExceptionRequiresForwardSecrecy will not require a justification for now. If used, this exception will be granted automatic approval. This is likely to change in future as forward secrecy becomes more widely spread.

NSExceptionAllowsInsecureHTTPLoads and NSExceptionMinimumTLSVersion will all require a reasonable justification for use.

Step 4: Configure ATS Exceptions (optional)

ATS Exceptions can be configured in the Toolkit via the “Configure iOS ATS” section of the request module configuration:

If you want to edit your app’s src/config.json file directly you may find the syntax is a little more obscure:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

"request":{

"version":"2.8",

"config":{

"disable_ats":false,

"ats":[

{

"domain":"httpbin.org",

"NSThirdPartyExceptionAllowsInsecureHTTPLoads":true,

"NSThirdPartyExceptionRequiresForwardSecrecy":true

}

]

}

},

The format is an array of objects each with a domain and a set of one or more keys such as NSThirdPartyExceptionAllowsInsecureHTTPLoads that can be set to true for each kind of exception you want to add.

The example above corresponds to the Toolkit screenshot and it requests the following exceptions for all requests to the domain httpbin.org:

Override ATS for HTTP requests to httpbin.org, a domain we do not control. If we did control this domain we’d have used the NSExceptionAllowsInsecureHTTPLoads key instead.

Override the Forward Secrecy requirement for any HTTPS requests to httpbin.org.

The fine print

Whereas these agreements were previously with WebMynd Inc., they have now been transferred to Trigger Corp, Inc.

Trigger Corp, Inc. is a Delaware corporation and a wholly owned subsidiary of Zazpi (Pty) Ltd, Reg no: 2014/064494, a South African limited liability company with offices at:

35 Cockburn Rd

Glencairn Heights

Cape Town

South Africa 7975

No other changes have been made.

What’s next?

Earlier this year I promised that we’ll be providing an alternative to StackOverflow for community support and communication.

We’re live right now at: https://community.trigger.io and I hope you will join me there if you have any questions regarding the ownership change.

I’m also available via email at support@trigger.io if you have any questions or would like to set up a Skype call.

Finally, I’d like to thank Amir, James, Connor, Tim, David and the many good people who have worked with us over the years for the immense contribution they’ve made to the business and wish them the very best in their present and future endaevours.

This week we’re going to be taking a look at a great Open Source project started by Trigger.io user Andres Olave:

ngForge provides a set of idiomatic AngularJS wrappers for the
Forge modules that allow for easy & clean integration with Google’s AngularJS framework.

Here, in his own words, is Andres to tell you all about it…

An Introduction to ngForge

Angular & Trigger.IO are a great combination for developing mobile apps. Using either iOS or Crosswalk for Android it’s possible to build hybrid mobile apps we could only dream of in the past few years.

ngForge is a set of Angular wrappers for Trigger.io Forge modules with the aim to:

Seemlessly switch between mobile & browser implementations

Provide a AngularJS friendly experience:

Dependency Injection not globals.

Promises not callbacks.

$http API equivalency for the request module.

Provide a basis for use in modern JS development:

Use the browser as the primary development environment – because there are many commonplace, well supported, free tools.

Don’t require trigger.io builds in the browser environment.

Be optimised for standard JS build tools: Grunt, Gulp, etc.

Allow services to be configured & reconfigured on the fly in browser mode.

How it works

Using AngularJS emphasises the use of dependency injection. The typical use is to inject services into controllers, or the Angular’s $http service into services.

Let’s say you are building a web app with a service that has a saveLocally method:

1

2

3

4

5

6

7

8

9

angular.module("app")

.service("UserService",["$localStorage",function(localStorage){

return{

saveLocally:function(id,user){

localStorage.setItem(id,JSON.stringify(user));

}

};

}]);

With ngForge you can now instead use $forgePrefs which delegates to the forge.prefs module when running as a mobile app, and to localStorage when running in a browser.

For example, we can inject it into any service implemented in Angular:

1

2

3

4

5

6

7

8

9

angular.module(‘app’)

.service(‘UserService’,[‘$forgePrefs’,function($forgePrefs){

return{

saveLocally:function(id,user){

$forgePrefs.set(id,user)

}

};

}]);

This way AngularJS allows us to implement the service before it provides the $forgePrefs service and ngForge can detect whether it is running in a mobile environment or a browser.

if it’s a mobile environment ngForge delegates all service calls to the Trigger.io module.

if it’s a browser environment ngForge:

returns mock data – for example $forgeContacts returns mock data.

and/or implements a mock version of the module – for example $forgePrefs delegates to localStorage in browser mode.

In fact even if ngForge doesn’t mock out a method, it is still able to delegate service calls to Trigger.io in mobile environment mode.

Promises NOT callbacks

The Forge module API’s are currently still based on Node.js-style callbacks which often lead to callback hell and are not a natural fit with Angular’s Promises-based approach to deferred and asynchronous computation.

ngForge extends the Forge Module API’s with support for Promises which allows you to use them in the same way as you would in your regular Angular app.

For example, using standard Trigger.io you’d access forge.prefs like this:

1

2

3

4

5

6

7

8

9

forge.prefs.get("userId",

function(value){

forge.logging.log("UserId: "+value);

},

function(){

forge.logging.log("Error occured");

}

);

With Promises, it instead becomes:

1

2

3

4

5

6

7

8

$forgePrefs.get(‘userId’)

.then(function(value){

forge.logging.log(“UserId:”+value);

})

.catch(function(){

forge.logging.log(“Error occured”);

});

Much cleaner wouldn’t you agree?

Service Configuration

In browser mode, ngForge services can be configured by using Angular config methods. You may want to configure:

Mock data: for example the mock contact book data used by $forgeContact, or

Implementation configuration, for example what key to store data under when using the localStorage version of $forgePrefs.

Each service documents what is configurable. Here is an example config:

1

2

3

4

5

angular.module(‘app’)

.config([‘$forgePrefsProvider’,function($forgePrefsProvider){

$forgePrefsProvider.prefsKey=‘customPrefix’

}]);

Using $forgeHttp instead of the forge.request module

However, the request module’s API is based on a subset of the JQuery API and if you are using Angular it would be preferable to replicate the $http service API. (See the Angular $http service documentation for more details.)

This is what the $forgeHttp API looks like:

1

2

3

4

5

6

7

8

$http.get(url,config)

$http.head(url,config)

$http.patch(url,data,config)

$http.post(url,data,config)

$http.put(url,data,config)

$http.delete(url,config)

$http.jsonp(url,config)

The following methods are not implemented as yet:

1

2

$http(config)

Additionally, the config object supports the following properties:

params – {string|Object}: Params that are not already query strings are serialized as query strings and appended to the URL.

data – {Object}: Data to be sent as the request message data. If it’s a get request then it is serialized as a query string and appended to the URL.

All these methods return a promise that support the standard methods: then, catch & finally methods that take function with a single argument of the http response object. It also supports the deprecated success & error methods for handling responses. See the Angular Promises Documentation for more detail.

There are some exciting Trigger.io updates coming that will make it possible for us to update ngForge with support for Angular 2 and Observables and we are planning broad framework support for ngForge in the near future.

Anyone who wants to talk about whatever is on their mind can quickly reach out to a trained, compassionate listener through our network. We have hundreds of listeners who come from all walks of life and have diverse experiences.

Glen Moriarty, Founder and CEO, is a psychologist who is passionate about the Internet’s power to help people lead better lives. He is joined by a team of professionals with a wide range of capabilities, from counselling and social work to engineering and web design.

Working with Trigger.io

We asked Ezra Morse, the Full Stack Engineer at 7 Cups, to tell us a little about working with Trigger.io as a platform for development.

Q – Why did 7cups choose to work with Trigger.io?

As the world’s largest emotional support network, 7 Cups is about bringing people together. The last thing we need is to sacrifice dev time on hunting for platform bugs, solving plug-in conflicts and triaging build issues.

Trigger.io allowed us to swiftly convert a legacy, first-generation mobile website into a reactive one-page application with the native plug-ins we needed, while keeping our focus where it should be: on user experience and our community.

In the end, we were able to produce a lean, performant app that isn’t mired by stability issues or the long iterative cycles characteristic of a fully native app. We finally have a stable and evolving application that better positions us to reach more people in need.

Q – What is your overall experience of hybrid development in today’s market?

To be honest, Trigger.io wasn’t our first choice on this project. Let’s just say that our first pass at modernizing our app could be described as wanting to have our cake and eat it too.

We bought into too many promises and tried to relegate far too much functionality (UX included) to the native device, thereby leaving us with a slow, bloated hybrid-application that would crash as often as freeze. So we went from an extremely bad scenario where our concerns about speed and the memory footprint of the app simply didn’t allow us to take any chances.

If we wanted to keep our app hybrid, a cordova-flavor just wasn’t going to give us the lean and stable app we wanted to share with the world; we simply could not afford to have performance issues continue to stand in between the people on each end of the device.

In summary, I feel a lot of the hybrid approaches fail to keep it simple on both the application level and the build process, and thereby, the end product suffers. As hybrid developers, should we really need to focus on too much more than what is going on inside that single webview?

Thanks Ezra, for making the time to speak to us and fill us in on your development process. We look forward to many more collaborations in the coming months.

Today I’ll be covering the support we’ve added for managing iOS and Android runtime permissions and showing you:

How you can use our Runtime Permission features to increase your app install rates.

How to dynamically adapt your app to the permission preferences of your users.

How to save your users from an epic journey into their device preferences if they didn’t grant an app permission the first time round.

What Are Runtime Permissions?

Both iOS and Android apps execute inside a sandboxed environment which places hard restrictions on the device resources accessible by your app.

The goal of this sandboxed environment is to limit the amount of mischief a malicious or misbehaving app can inflict on your device.

In a perfectly secure world, apps would not be able to access any resource outside of their own environment. Unfortunately this would also mean we could not develop apps that make use of device features such as cameras, photo albums, geolocation or notifications.

The compromise then is for apps to explicitly request the user to grant specific “device permissions” to the app.

This informs your users of the device capabilities they are entrusting to your app, but it also places the onus on you, the app developer, to give the user a reason to trust you!

On older versions of Android, and a lesser extent iOS, the user was forced into an all-or-nothing decision about whether to grant access to resources during the initial app installation process.

Given how long the list of requested device permissions can get this unfortunately results in many users responding to such a big “ask” by simply not installing the app.

It’s a little hard to win your user’s trust if they’re not running your app in the first place, right?

Luckily, with the release of Android Marshmallow, Forge v2.4 and our new forge.permissions module, users no longer have to make an upfront leap of faith as it’s now possible to incrementally request device permissions at runtime on both iOS and Android.

This helps your users feel more in control, while simultaneously giving you a chance to make a powerful case for the benefits of trusting you with their device.

Forge and Runtime Permissions

Up till now, the way we’ve dealt with runtime permission requests on iOS and Android Marshmallow has been to automatically trigger the system permission request dialog whenever a module calls a native API requiring that permission.

For example:

1

2

3

4

5

6

7

8

9

10

11

12

// this will trigger a permission request

forge.contact.selectAll(function(contact){

// user has given permission, do stuff with contact

},function(error){

if(error.message.indexOf("Permission Denied")===0){

// disable app feature and maybe display an explanatory message

}else{

// handle any other errors

}

});

Which results in an app flow that looks like this:

The good news is that this behaviour has not changed with the release of v2.4 and if you’re satisfied with the way your app works you can stop reading right now.

However, an important gotcha to be aware of is that both Android and iOS devices have the following behaviours hardcoded into their operating systems:

On Android: When a user clicks “No” the first time they are asked, they will have the option to prevent the app from making subsequent requests.

On iOS: When a user clicks “No” the first time they are asked, the app will be prevented from making subsequent requests.

What this means is that once a permission request has been denied, there is a high likelihood that the only way the user can grant that permission in future is by digging in their device’s System Preferences.

Or to put it another way, once a permission request has been denied (iOS) or disabled (Android) all future requests to forge.contact.selectAll() will only ever trigger the error callback.

Not an ideal situation, but all is not lost!

We created the forge.permissions module to address precisely this problem and to help you get more control over when and how permission requests are presented.

How To Use The forge.permissions Module

Step 0: Update your platform version and modules to the latest versions

To use the forge.permissions module you need to be on at least platform version v2.4.1 and at least the following module versions:

module

version

contact

2.9

calendar

2.7

geolocation

2.4

camera

2.3

file

2.11

Step 1: Add the permissions module to your app

In the modules section of your app’s src/config.json file add the module as follows:

1

2

3

4

5

6

7

"modules":{

...

"permissions":{

"version":"1.0"

}

}

Alternatively, launch the Trigger.io Toolkit and navigate to the Modules section of your app and search for the permissions module.

Step 2: Check Whether You Need To Make A Permission Request

Before we actually request a permission we first need to check whether the user has already granted the permission or not.

Once we know this, we will know whether we will need to initiate a permissions request or whether we can proceed normally with our app.

The API that will give us this information is: forge.permissions.check()

So, let’s say we have a feature that needs to use the forge.contact.selectAll() API which relies on the forge.permissions.contacts.read permission.

Note that, although the user will be presented with the permissions popup when you call forge.permissions.request() this is slightly deceptive.

The dialog the user will see is not generated by the device operating system but rather by the module. If the user clicks “No” in this dialog any future requests for the permission will no longer fail automatically.

It is only after the user has clicked “Yes” that the real system dialog is presented.

With this code, your user will be asked for permission when you call forge.permissions.request() and you then have the option to take an alternate action if the user did not grant the request.

All Together Now

Now that you know how to check for and request permissions, let’s look at an example of how you could put all the pieces together for a smooth user experience in your app:

There are a couple of advantages to doing it this way:

The call to forge.permissions.check() provides a logical place to fork your app logic depending on whether the user has already granted the permission or not.

By linking the forge.permissions.request() call to a user action which explicitly relates to the permission being requested you greatly reduce uncertainty in the user’s mind about the purpose of the permission request.

Being able to check the outcome of the permission request you’re able to easily update your application and explain to the user why you need access to that permission.

That said, this is only one example of how to do it and you may find your application needs a different approach.

Conclusion

I hope you enjoyed this quick journey through the iOS & Android Runtime Permissions models, how Forge handles permissions by default and the tutorial on how to use the forge.permissions module to implement custom handling of runtime permissions.

We’ll be covering the individual features landing with v2.4.1 in more detail over the coming weeks but let’s take a quick look at the highlights:

New forge build target: Crosswalk

With the release of Trigger.io Forge v2.4.1 our crosswalk target has finally graduated from the beta branch and has been declared ready for production use.

Anyone developing hybrid apps for Android will be familiar with the myriad of compatibility issues that pop up when you start testing your app against different versions of Android.

Android versions before v4.4 shipped with a proprietary System WebView which lacked many basic HTML5 features, performed poorly and suffered from compatibility issues.

Android versions after v4.4 use whichever version of the Chrome-based System WebView was current when the device shipped.

The very latest versions of Android now periodically update the System WebView when newer versions of Chrome are released but this creates new problems when System WebView changes suddenly render your code inoperable.

Runtime App Permissions

With the release of Trigger.io Forge v2.4.1 and our new forge.permissions module we fully support the new Android Runtime Permissions framework and give you complete control over when and how your app makes native permission requests.

By default, all forge module API’s will now only make a request to the user for permissions when the API is called and not during application startup.

While this has the benefit of not requiring a user to make an “all-or-nothing” decision when they install the app it still has the downside that it can quickly get quite complex to handle situations where users deny permission requests.

By using the forge.permissions module you have fine-grained control over permission management, can easily handle cases where permissions are denied and greatly increase the probability that users will grant your app the permissions it requires.

Android Studio Support

While we’re huge fans of the IntelliJ IDEA-based Android Studio the primary motivator for this shift came about because Google have now officially deprecated Eclipse for Android development.

This means that all development and official support for the Android Developer Tools (ADT) in Eclipse have now ended. Specifically, this includes the ADT plugin as well as the Android ant build system.

We’ll continue to support native module development with ant and Eclipse for as long as practical but you may be pleasantly surprised at how much easier Native Module development can be with Gradle & Android Studio!

Upgrade your app to Trigger.io Forge v2.4.1

You can find more information in the v2.4.1 release notes but the following steps should get you going:

Step 1 – Upgrade your platform version

Open your app’s src/config.json file in your favorite text editor and set the platform_version key to v2.4.1 as follows:

In Conclusion

v2.4.1 is a massive release for us and represents the culmination of almost a year’s worth of engineering effort.

The complexity of integrating a new Forge runtime while simultaneously migrating our Android build system over to Gradle has been non-trivial and I’d like to give a special shout out to:

The v2.3beta branch testers who tirelessly hammered on each release, reported bugs and – often – contributed hours of their time to help us track down and reproduce issues. Y’all know who you are, thank you!

The Crosswalk team @ Intel. Crosswalk is beautifully engineered so it was rare that we got stuck, but when we did you were there with rapid responses, answers and marketing support!

Finally, if you run into any issues with v2.4.1 or have any questions about this release please don’t hesitate to get in touch with us at support@trigger.io.

Dear Trigger developers,

Well here we are again. The year is drawing to a close, there’s a definite festive spirit in the air and I’m wondering where the time has gone.

2015 has been a landmark year for Trigger.io and I’m pleased as punch to share that we are once again showing stable month-on-month growth. This marks the completion of the transitionary period from externally-funded startup
to a sustainable business and is a reliable indicator that we will continue to be here for all of you, now and in the future.

We wouldn’t have come this far without the willingness of the Trigger.io community to bet on us. So from our oldest customers who have been with us since we were in beta to our newest customers who only joined this week:

“Thank you, you rock!”

I’m not going to get into details on the engineering work we have planned for the new year as I covered it last month. Instead, I’d like to talk about the softer side of the platform.

Over the last couple of weeks I’ve heard from many of you with suggestions and questions about what 2016 holds in store. The dominant theme in all these conversations have been that it’s time for us to put energy and
resources into the Trigger.IO community.

Based on these conversations, some of the things we’d like to look at are:

Finally, our offices will be shutting down on the 15th of December 2015 and will open again on the 7th of January. We will however have someone checking in on support during this time in case any emergencies come up.

Wishing everyone a fantastic holiday to recharge for the coming year, I have a feeling it’s going to be a great one!

I’ll be honest, surfing this tsunami of change isn’t always fun but once in a while I’ll come across something that reminds me of the value of what we do:

I don’t want to get into a rant about the kind of thinking responsible for this state of affairs but I would like to place it in perspective:

If, twenty years ago, you compiled a C/C++ application for the Windows WIN32 API using C/C++ there is every chance that your original binary executable will still work on Microsoft’s latest Windows 10 release.

Binary compatibility is unfortunately out of our reach and it’s still too early to tell if Trigger.IO will match Microsoft’s track record but we’re certainly giving it the old college try.

Simply put:

If you shipped a HTML/CSS/JS Trigger.IO app in 2012 chances are very, very good that it will still run on the latest versions of iOS and Android without requiring anything more from your side than a forge build ios && forge build android.

Your legacy? It matters to us.

Platform Version 2.4

The road to 2.4 has been long and I know a lot of you have been patiently waiting for the Crosswalk support from our beta branch to finally make its way to stable release.

Well, I’m pleased to announce that today we finished the last major piece of work that has been holding this back!

Basically, we had two major blockers:

The Ant build system had problems dealing with application resources from multiple external libraries which led to all kinds of horrible bugs when using Crosswalk with some native modules.

There was no simple way to test custom native modules in both the Android and Crosswalk environments.

The resolution wasn’t simple but, ironically, it came in the form of the kind of announcement we’d normally dread: