Categories
Tutorial

React Native URL Scheme and Linking API

React Native is possible the best hybrid framework for building mobile app at the moment. Not just its performance but also the development experience it provides. If you build it well, one really can’t tell if your app is native or a hybrid.

I spent my last 3 month developing a complicated hybrid app using react native. It involves many network requests, forms, lists, etc. It was undoubtedly challenging, but the result was quite satisfying.

For my next project, I was given another chance to work with React Native. This time I need to build a “AppStore” kind of application, which allow the user to install apps and launch installed apps right from this custom “AppStore”.

To launch other Apps in iOS or Android, we must register custom URL Schemes in the Apps we wish to launch.

Register URL Schemes

iOS

On iOS, we need to add a key CFBundleURLTYpes to the Info.plist file within the Xcode project.

Under this key we add an array, and define 2 keys CFBundleURLName and CFBundleURLSchemes.

Under CFBundleURLName you need to add a unique string that identifies your bundle, I used the same string as my app’s bundle identifier and it worked fine. Under CFBundleURLSchemes you need to add another array, and put in your desired URL schemes.

Here is an example of such entry inside Info.plist:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>com.johnsonsu.example</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>johnsonsu-example</string>
        </array>
    </dict>
</array>

More info about iOS URL Scheme can be found on the official documentation.

Android

Android’s setup is similar to iOS. We need to add a custom intent-filter in the Android app’s AndroidManifest.xml file.

Here is an example of such intent-filter:

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <data android:scheme="johnsonsu-example"/>
</intent-filter>

Since React Native’s Linking API will be creating an intent with action equals to android.intent.action.VIEW, your intent-filter must contain an action tag with this name.

The data tag is where you should define your custom URL Scheme. In this example I used the same one as the iOS scheme. Doing it this way allows me to use the exact same code in React Native to launch these applications in both iOS and Android.

More info about Android Intent Filter can be found on the official documentation.

Launching the App in React Native

If you setup your apps properly, you should be able to launch that app in React Native using:

import { Linking } from 'react-native';

Linking.openURL('johnsonsu-example://').catch(err => console.error('An error occurred', err));

If the OS can’t handle the URL you tried to open, the exception will be caught inside the catch block, and you should handle it properly to prevent a crash.

A safer way to open URL is to check if the OS can handle it before you open it. You can check it using:

import { Linking } from 'react-native';

const url = 'johnsonsu-example://';
Linking.canOpenURL(url).then(supported => {
  if (!supported) {
    console.log('Can\'t handle url: ' + url);
  } else {
    return Linking.openURL(url);
  }
}).catch(err => console.error('An error occurred', err));

This works on Android without any setup. However, on iOS 9 or above, you need to add LSApplicationQueriesSchemes to your React Native app’s Info.plist or Linking.canOpenURL(url) will always returns false.

This is an example entry in Info.plist:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>johnsonsu-example</string>
    <string>youtube</string>
    <string>facebook</string>
</array>

There you have it, a simple way to launch any other apps from your React Native app!

Categories
Uncategorized

Fix iOS 8.1.2 Jailbreak Jetsam Events and Random Respring

I always enjoyed jailbreaking my iPhone. The freedoms of modifying whatever you want and using tweaks are great add-ons to the already amazing phone.

However, one of the main drawback on jailbreaking is the instability it introduces. Phones can become malfunctioning if it was not tweaked properly. Random Respring is a common instability symptom of a jailbroken phone. This can be caused by many things, tweaks crashing, tweak conflicts, memory leaks and so on.

Not so long ago, my iPhone started to Respring randomly. When this happens, first thing to do is go to

    Settings > Privacy > Diagnostics & Usage > Diagnostics & Usage Data 

to check the error log. At first, you might have a hard time looking for the crash log corresponding to your Respring, but once you identified the type of crash, it will get easier.

IMG_4716

My Respring was caused by a Jetsam Event, this indicates memory insufficient problems. This event will be fired if the phone is out of memory, and it needs to close some App. However, Jetsam usually shuts down Apps running in the background, not the SpringBoard process which manages your home screen, lock screen etc.

IMG_4717

Open up the error log, and we can see that the largest process was SpringBoard, which is abnormal. This indicates that the Respring is very likely caused by the tweaks I installed. The best way to solve this problem is to uninstall recently installed tweaks, especially those related to SpringBoard, like custom lock screens.

It is also a good idea to check if any of the tweaks you installed is not compatible with the version of iOS you have on your phone. Many lists of compatible tweaks is available online, here is one of them.

At the end, it turns out that all the random Respring was caused by the Cataracs, GroovyLock and LockHTML. My phone has been very stable since I removed all 3 tweaks.

Categories
Tutorial

Adding “Pull to refresh” to IOS 8

Recently I have started working on an IOS client application for the web-app I created earlier.

In this IOS app, I have a UITableView that display projects fetched from a web-server. A typical function for this kind of data-fetching view controller is “refresh”, which is a simple call to the server, download the most update data, and reload the table.

When I implement “pull to refresh” in the past (around ios 5), I would use open source libraries from github to help me, avoid “reinventing the wheel”. However, that is now a thing of the past, Xcode now allows you to add “pull to refresh” without adding any extra libraries. The best thing is it only takes a few minute to get it working.

 

Add UIRefreshControl

Screen Shot 2015-01-12 at 5.48.37 PM

 

In your storyboard, go and select the UITableViewController that you wish to add the “pull to refresh” function. Then on the right panel, select the Attribute Inspector tab, and switch “Refreshing” from Disabled to Enabled.

Screen Shot 2015-01-12 at 5.47.13 PM

Doing this Xcode will generate a UIRefreshController for your UITableViewController, which we can see on the Document Outline on the left.

Now we open the Assistant Editor and Ctrl+Drag the Refresh Control from the Document Outline directly to your UITableViewController.m file, creating a IBAction function like you do with of your buttons.

Screen Shot 2015-01-12 at 5.54.47 PM

 

I will simply call my function refresh, and all it does is call a loadProject function that will fetch data and reload the table.

- (IBAction)refresh:(UIRefreshControl *)sender {
    [self loadProjects];
    [sender endRefreshing];
}

One thing to note here is you need to call [sender endRefreshing]; to stop the loading indicator from spinning forever.

Done! Now you may build and run your application and see the pull to refresh in action.