Monthly Archives: January 2016

Getting Started with NativeScript - On Sale Now!

Getting Started with NativeScript

Getting Started with NativeScript

WooHoo!   It has been such a long road to get this book published.   I wrote a bit about it here.  It is finally  officially available on the Packt site for sale today!   It should be available on the Amazon store by Monday the 1st of February.  I will have a list of additional sites and urls later this week.  If you want the best book on NativeScript (I know I'm so funny!  I get to claim it because its the only book on NativeScript!) then it is now available!

The available sites are as follows:

 

 

 

NativeScript and WebWorkers/Threads

gears-148196_960_720So about 10 months ago, I put in an issue for adding threads/workers to NativeScript.  I realized early on this was a major feature that is missing.  10 months later, I still have that same opinion; the only real major feature NativeScript is really missing is background threads.   For a lot of projects this won't have an effect; but their are those that need to do processing and this missing feature is a major problem for these types of applications as there has not been a good way to work around it.

Well mid-last week, a user x4080 posted a question about if WebViews main thread is tied to the NativeScript main thread or if it could be used as another thread.  Light bulb went on in my head --  awesome thinking outside the box by x4080!     I quickly created a test framework using an existing app I had written and tested it.   The threads are distinct!   Fast forward a couple days and today, I am happy to announce nativescript-webworkers!   I have wrapped everything up on Android so that it works like a just like a traditional WebWorker with extras!  iOS support should be later this week.

To install you just need to do the standard nativescript plugin add nativescript-webworkers then you can follow my simple sample in the docs or any of the countless myriad of webworker examples on the web.   This does obviously increase the ram required and their is a startup cost for the webworker to be primed and ready to run.    But if you have any processing you don't want on the main thread; we now have a solution that should solve most use cases where more than one thread is needed.

 

 

 

Git submodule and shallow clones

This tip is more for my records because I am having to look up this information since it is not something I use all the time.    However, I hope it helps some of you too.  You do need a recent version of git.

If you have a submodule that has a REALLY large history and you only need the current head to build; do a simple:

git submodule init
git submodule update --depth 1

To clone to specific commit; you can do:
git submodule init
cd submodule_folder
git fetch --depth=1 origin COMMIT_ID
cd ..
git submodule update

To clone a specific tag:
git submodule init
cd submodule_folder
git fetch --depth 1 origin refs/tags/TAG_NAME
cd ..git submodule update

Hopefully these will save you (& me) some time in the future.

NativeScript: Page navigating order of events

Duals_graphsI'm always having to reference my own notes to remember this; so I figured I would put a blog article up describing this so that everyone can benefit from my forgetfulness.   😉

Navigating
When you do a frame.topmost().navigate('destinationPage');  there is a specific order of events;

Source page fires: navigatingFrom
Destination page fires: navigatingTo
Source page fires: navigatedFrom
Source page fired: unloaded
Destination page fires: loaded
Destination page fires: navigatedTo

Modal Screen
If you are using a sourcePage.showModal('modalPage','',callback); the events are different.

Modal page fires: loaded
Modal page fires: showingModally (v1.60+ event)
Modal page fires: shownModally

on closing the modal:
Modal page fires: unloaded
Source page is in callback you provide the showModal function

Gotcha's

  • Currently in NativeScript you cannot cancel a navigation. (Might show up in v1.6, per bug #583)
  • On iOS you can't use page.showModal in page loaded event; you must wait until the navigatedTo event.   (This appears to be fixed in v1.5 per bug #779)
  • On iOS; if you are using animation the destination page loaded event is fired after the page animates in.  If you need need to have bindings evaluated to make your interface look nice you need to use the navigatingTo event to setup the binding.
  • Do not use anything frame related in the navigatingTo event; the page has not been fully initialized until the loaded event is fired.  The also applied to some page functions like showModal & getViewById.  In other words; be very careful when messing with the new page in the navigatingTo event.  This is the expected behavior; so do not file a bug report.  The onNavigatingTo event is telling you that it is going to load this page.

If you have any more gotcha that I haven't seen; please feel free to comment.  As usual; if you have any ideas for blog posts; please feel free to ask.

Fonter - Revisited (iOS & Android NativeScript Fonts)

In my prior post on fonter, I walked though how to use the text fonts.  Several things have changed from that point in time; including iOS now auto-registers the fonts.  So I want to revisit the information and cover what needs to happen with NativeScript 1.5.1 and newer.

Setup
font-folderThe folder structure is still the same; you still have to create and use the fonts folder inside your app folder.  All font files are placed in that folder.  Remember this folder is a folder you will have to initially create as it is not created for you by NativeScript when it creates the project for you.

CSS Rules
In the CSS rules, the first font declaration is the one you want to have auto-register.  It is the filename of the actual file without the .ttf.  So if the file name is called JosefinSans-Regular.ttf, then the CSS rule would be:

.JosefinSans {
    font-family:JosefinSans-Regular,Josefin Sans;
}

The second declaration is the actual internal font name.   Android only needs the first declaration; on iOS you might need to have them both.  In most cases iOS does appear now to be able to use the font filename; however I have found in some case it still requires the actual internal font name -- so I recommend you include both since it is simpler and you make sure it will work on iOS and Android.

To figure out the internal font name for iOS the procedure is the same as I outlined before; double click on the font, and then look for the font name in the place I highlighted.

 

font-titlebar-winfont-titlebar-osx

Using Fonts
The key to using fonts is to use the class or cssclass in the Declaritive XML; so a Label then has attache <Label text="Cool Text" class="JosefinSans"/> would cause the .JosefinSans css rule to be applied to this Label. Which would mean the "Cool Text" would use the Josefin Sans font since that is what we put in the .JosefinSans css rule above.  This the same for all types of fonts, you create the CSS rule with a font-family and then apply it to the Declarative UI element with the cssclass/class on it.

Using Icon Fonts
The new version of Fonter includes not only the three standard text fonts; but I also include three different icon fonts.

  • Google's Material Design
  • Fontastic
  • Material-Design-Iconic

Using Google Material Design Fonts
Lets tackle Google's Material Design first, the thing you need to do is go to to the Material Design website. On this website you can look through the different icons.  So in the second row of icons you should see a picture of the android.  Click on it and you will see at the bottom of the screen a blue bar appear.

GoogleOnce the blue bar appears; click the bottom right corner (highlighted in red) where it says Icon Font.  It will popup a bit more and show the entire grey screen, and you should see towards the bottom of the screen some text that I highlighed in blue that looks like this: <i class="material-icons">&#xE859;</i>.   You see the bolded value?   That is what you need to copy to use this icon in your nativescript application.

Fontawesome
Now we need to go to the Fontawesome website.  In this case it is much simpler, scroll the cheatsheet until you find the icon you want to use.  Then copy the &#x.... number.  For example at the top the fa-500px icon would be &#xf26e;. Pretty simple to find on Fontawesome's site.

Material-Design-Iconic
GMDThe final site we need to go to is the Material Design Iconic website.  Just like the Google site; you need to click on the icon to see the code.  So find the icon you want and click on it.  And you should see something like this.

The text highlighted in red is the important information.  For this icon is say f33b. You prefix that with the &#x and append a semicolon so it will be &#xf33b;.  And that gives you the code for Google-Material-Iconic

Using the Codes
As you can see all three codes use the same format; NativeScript can use the html entity codes inside the XML to display the characters.   So as an example I am going to show you how I use the Fontastic font; My XML is:

<Label android:text=" &#xf17b; " ios:text=" &#xf179; " cssClass="FontAwesome"/>

As you might notice, on Android I am showing the Android picture, on iOS I'm showing the Apple logo.   My app.css is this:

.FontAwesome {
    font-family: FontAwesome;
}

That is all that is required to make it work.  Proper CSS, XML, and finally the font in the app/fonts folder.

Now their is one other thing that also gets frequently asked, is how do you do the same things from JavaScript like for a bound control.  Well first you still need a control that has the proper CSS applied to it.   To assign a icon character from JavaScript can be done one of two ways.

Option 1:
var myChar = "\uf33b";

Option 2:
var myChar = String.fromCharCode(parseInt('f33b', 16));

In Javascript you can use \uXXXX where the XXXX is the 4 hex characters after the &#x, the \u acts in JavaScript just like the &#x does in XML.  The other options is to use the String.fromCharCode(parseInt('XXXX',16)) and use the same XXXX as the \u would require.  We have to convert the String hexadecimal values into an integer value for this to work.  However if you manually convert it yourself, then you can eliminate the parseInt() code.   So in this case 0xf33b = 62267, so you can do var myChar = String.fromCharCode(62267);

fonter-androidYou can download the full demo application fonter102, which has all 6 fonts, all the css and the xml used to display properly on iOS and Android.

Please note; this REQURES the latest tns-core-modules; 1.5.1 on iOS and v1.5.0 or greater on Android.   If you are using an earlier version of the core modules then you should read my prior fonter post from how you need to setup the iOS registration.

 

If you have any other ideas for blog posts; feel free to comment.

Creating a plugin using third party code

So, I was minding my own business last week, by reading about everyone's issues in the NativeScript forum.  Well, ok, so I wasn't minding my own business, we can pretend I was...

So, I saw this post about CodeSign error: entitlements are required and tried to help a little. The issue actually ends up being the newest version of XCode has some issues that has been causing problems for people in all sorts of communities.

Well, I told Aaron, I would do a blog post the next day on the plugin.  My how time flies when you are swamped with stuff to do and it also being Christmas week; so it has been a week since I said the next day.   (Sorry, about that Aaron!)

NS-ZXingSo I am going to go with his ZXing plugin that he was trying to turn into a NativeScript plugin to show how to native Android and native iOS libraries and turn them into awesome NativeScript plugins.

If you just want to look at the code or demo the repo is at https://github.com/NathanaelA/nativescript-zxing.  So here is how I go about making a plugin in from a native library.

  1. Find the iOS (ZXingObjC) and Android (ZXing) versions.
  2. Study the documentation to see how to install them & build the platform files.
  3. Study the documentation to see how to call them & build the js wrappers.

foldersFirst thing we need to do is create a new project folder; since this is for ZXing; I created a folder called nativescript-zxing.  In this folder I created a several files.

The LICENSE file
The first file is the LICENSE file; I need to make sure that I give credit where credit is due and outline my license and the library authors licenses.  Most the time I use a MIT license for my stuff; however in this case since both the iOS & Android parts are already under the Apache license, I used the Apache license to keep everything the same.

The package.json
The second file is the package.json file.  This one pretty straight forward, however since I have seen several mistakes in other NativeScript plugins, I am going to cover it.

{
  "name": "nativescript-zxing",
  "version": "1.0.0",
  "description": "A Simple ZXing barcode reader/writer wrapper",
  "main": "zxing.js",
  "nativescript": {
   "platforms": {
      "android": "1.4.0",
        "ios": "1.4.0"
   }
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/nathanaela/nativescript-zxing.git"
  },
  "keywords": [
    "NativeScript", "Barcode", "JavaScript", "Android", "iOS", "ZXing"
  ],
  "author": {
    "name": "Nathanael Anderson",
    "email": "nathan@master-technology.com"
  },
  "bugs": {
    "url": "https://github.com/nathanaela/nativescript-zxing/issues"
  },
  "license": {
    "type": "APACHE",
    "url": "https://github.com/nathanaela/nativescript-zxing/blob/master/LICENSE"
  },
  "homepage": "https://github.com/nathanaela/nativescript-zxing",
  "readmeFilename": "README.md"
}

The important parts are:

  1. You must have the nativescript.platforms key section like I have.  If you are not supporting iOS or Android you can remove one of those sub-keys; but you need to support at least one valid platform.  Please note this version you use is the minimum platform version you support.  DO NOT SET IT TO THE LATEST version unless it absolutely requires the latest version.  Please use 1.x.0 so that it will work on all versions of 1.x -- I don't know how many plugins I've had to manually change this value to work on the latest Android runtime, because the author put the latest iOS runtime in both spots which is later than the Android version, so it throws an error during install.
  2. It is highly recommended you have the main key set so that NativeScript isn't guessing which is your main JavaScript file.  This has causes problems several times so far, so set it.
  3. PLEASE link back to the repository for your plugin; it makes it a lot easier to report any issues, create pull requests and/or see if anything has been fixed, etc...
  4. Please include the license information, it makes is easier to verify that the plugin can be used for my project.

Android Runtime
So, lets start with the Android version; in this case after reading the documentation; I found out the wiki has the information we need to know.  Most the time the readme has enough information, but in this case I had to actually search for it, and finally found the pieces we need to know in the wiki.  The documentation has a nice little section on using a prebuilt Jar or Maven.  Since we are using Gradle for Android, we can use the Maven stuff and eliminate having to package up or compile anything (This is the best option).

However, in some cases if the project is no longer being maintained or you have to create your own fixes you may need to build and distribute the .jar or .aar file with your project like I need with my NativeScript-WebSockets project.  In the event you need to distribute your own JAR files; put them in the platforms/android/libs directory.

In our case, since the project is maintained and on Maven, we can easily just create a include.gradle and then NativeScript will handle the rest.  The include.gradle file needs to be put in the platforms/android folder.  The include.gradle file looks like this:

android { 
    productFlavors {
        "nativescript-zxing" {
            dimension "nativescript-zxing"
        }
    }
}

dependencies {
   compile 'com.google.zxing:android-core:3.2.1'
   compile 'com.google.zxing:core:3.2.1'  
}

In your file; you need to change both places for the plugin name.  And the dependencies is where we link to the our libraries.   Now how do I know what they are named?  Well first of all we used the Maven link from the Wiki documentation, and then went into the core folder to get the latest version.  3.2.1; The project is called com.google.zxing and it is a sub-project called core.  So the compile line is "compile 'com.google.zxing:core:3.2.1'".   The other compile line is an optional dependency that I decided to include on the Android side of the plugin.  I'm not currently using it in the JS code; but in future versions it would be very useful.  So I am including it in the build process. This is ALL that is required to get the Android version of the plugin to be built into your application.

iOS Runtime
The iOS runtime is much simpler as the docs on the site list what we need to know; we don't have to go searching anywhere else.  So what you need to is create a file called Podfile and place it in your platforms/ios folder.  This file contains a single line:

pod 'ZXingObjC', '~&gt; 3.0'

Now the installation says to put a platform :ios '7.0' into your Podfile; however this is NOT recommended since NativeScript is handling the platform information and will actually set it to 8.0 when you are using Podfiles.   So it is better to only add the single pod line.

We are now all done with the runtime side; the platforms/ios/Podfile and platforms/android/include.gradle will automatically download and install all the needed files to link it into your project.  The next part is where the fun begins...

Creating a cross platform wrapper
This where you have to put on your thinking hat.  You need to decide how you want your api to be called and what features you want to expose.  You can even do what NativeScript does in some cases and expose a ios or android property to access the underlying library. In our case the wrapper is going to be very simple; I just want to show you how do it.  All I am going to do is expose how to create a new barcode image.

iOS Wrapper
So first we need to create a zxing.ios.js file (please notice in my package.json I set the main key to "zxing.js").  NativeScript will automatically RENAME the .ios. version of the plugin when it is building your app on the iOS platform and strip out the .ios; so the file will become zxing.js automatically.

This file is a simple constructor that literally does nothing as I am trying to keep this example very simple.

function NativeZXing() {
    if (!this instanceof NativeZXing) { 
        return new NativeZXing();
    }
}

I do typically safe guards I try to add all of my plugins.  It simplifies usage of the plugin you can actually do "var zx = NativeZXing();" forgetting the "new" and it will still work since the constructor function will call new for them.  Some people prefer to throw an error rather than automatically using new.  My policy is in plugins attempt to be as user friendly as possible.

The next step is to create the function that will create a barcode.  So looking at the documentation the way to create a CGImage is this code:

ZXMultiFormatWriter *writer = [ZXMultiFormatWriter writer];
ZXBitMatrix* result = [writer encode:@"A string to encode"
                              format:kBarcodeFormatQRCode
                               width:500
                              height:500
                               error:&amp;error;
  CGImageRef image = [[ZXImage imageWithMatrix:result] cgimage];

So I decided our function will look like this...
NativeZXing.prototype.createBarcode = function(options) {
    var encode="NOTHING", width=100, height=100, format = this.QR_CODE;
    if (options) {
        if (options.encode) { encode = options.encode; }
        if (options.width) { width = options.width; }
        if (options.height) { height = options.height; }
        if (options.format) { format = options.format; }
    }
    var error = new interop.Reference();
    var writer = ZXMultiFormatWriter.writer();
    var result = writer.encodeFormatWidthHeightError(encode, format, width, height, error);
    
    if (result) {
        return UIImage.alloc().initWithCGImage(ZXImage.imageWithMatrix(result).cgimage);
    } else {
        return error.localizedDescription().toString();
    }
};

This first 7 lines are pretty simple; they set the defaults and allows the options dictionary to override the defaults.  These might be better as properties on the object, but for simplicity they are parameters.   The next line might not be so obvious; "var error = new interop.Reference();" In ObjectiveC anytime we need to pass a pointer/reference for marshalling into a runtime function call we need to create a reference.  If you look up above in the example; you will see error being passed as &error.  That  told me I needed to pre-create the reference so I could pass it in and get the result.   In most cases you can just pass null instead of an interop.Reference() if you don't want the results; but in this case I decided to capture the error.

The next line is an easy conversion; the Documentation says *writer = [ZXMultiFormatWriter writer] this converted into NativeScript is simply var writer = ZXMultiFormatWriter.writer();

The following line is a lot more complex to parse and really makes you have to think about how to convert it.  So looking at the [writer encode:@"A string to encode" format:kBarcodeFormatQRCode width:500 height:500 error:&error]. The rule is the first parameter is ignored, lets parse this.  The NativeScript code starts with writer.encode since that is the iOS call.  Skip the first parameter, then the next parameter is "format" so we append a proper cased "Format" to the writer.encode to make it writer.encodeFormat. We proceed through each of the following parameters and appending a proper cased version.  So the call finally ends up being writer.encodeFormatWidthHeightError(... params ...); Once you understand how it isn't too bad to parse.  However, the issue can be if the documentation is wrong and their are other parameters.  You MUST have every parameter accounted for in the function name for the NativeScript to be able to marshall the call into the iOS runtimes.

The next line just checks to see if we got a result; if so we convert it to an image or we return the error.  To convert the result into an image the next line is [[ZXImage imageWithMatrix:result] cgimage]  Again, the calls are not to hard to parse so this one ends up being; var image = ZXImage.imageWithMatix(result).cgimage;

Now in our plugin case I actually converted the CGImage into a UImage since all the NativeScript code seems to use UImage's.  So that the extra UIImage.alloc().initWithCGImage() code that I added.

The last two things I add to the wrapper are any ENUM or FEATURE flags, to keep consistency for your application code.   For example the format of the barcode can be chosen using format parameter.   Would your really want to add to you *application* code like  ZXBarcodeFormat.kBarcodeFormatQRCode; for iOS and com.google.zxing.BarcodeFormat.QR_CODE for android to determine that you are using QR code barcodes?   No, me either.  So I wrap the feature flags into JS feature flags like so:

NativeZXing.QR_CODE = NativeZXing.prototype.QR_CODE = ZXBarcodeFormat.kBarcodeFormatQRCode;

In this case since ZXing appears to only have a barcode types as the feature flags; I attach them directly.   But if ZXing had a lot of different features I would do something like this:
BARCODE = {QR_CODE: ZXBarcodeFormat.kBarcodeFormatQRCode,...};
NativeZXing.BARCODE = NativeZXing.prototype.BARCODE = BARCODE

And finally we next to export the entire module with this code:
module.exports = NativeZXing;

Awesome the code is complete on iOS.  When you createBarcode({encode: "Hi"}); you will get a UImage back on iOS.

Android Wrapper
Just like we did on iOS; we create a file called zxing.android.js.  In this file we have the exact same constructor, it also has the same module export statement.  However the actual code to generate the Image is different.  So here is the Android version.

NativeZXing.prototype.createBarcode = function(options) {
   var encode="NOTHING", width=100, height=100, format = this.QR_CODE;
   if (options) {
        if (options.encode) { encode = options.encode; }
        if (options.width) { width = options.width; }
        if (options.height) { height = options.height; }
        if (options.format) { format = options.format; }
    }
    var hints = null;
    var writer = new com.google.zxing.MultiFormatWriter();
    var result = writer.encode(encode, format, width, height, hints);
    width = result.getWidth();
    height = result.getHeight();
    var pixels = [];
    for (var y=0;y&lt;height;y++) {
        var offset = y*width;
        for (var x=0;x&lt;width;x++) {
            pixels[offset+x] = result.get(x,y) ? 0xFF000000 : 0xFFFFFFFF;  // Black : White
        }
    }
    var bitmap = android.graphics.Bitmap.createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888);
    bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
    return bitmap;
};

As you can see the first 7 lines are the same.  However, the writer line is different.  Typically the documentation will tell where in the namespace the function resides.  In this case I actually looked at the source code to determine where the MultiFormatWriter function was at.  It showed it was using "package com.google.zxing" namespace and is a class called MultiFormatWriter.    So that is converted to var writer = new com.google.zxing.MultiFormatWriter(); The next line is equally simple since we are looking at the source code (Documentation is typically easier, but in this case the source was quicker). So it is called exactly as it is displayed in the source code: var result = writer.encode(encode, format, width, height, hints);

The examples I found on how to use MultiFormatWriter and convert it to an image; showed us basically scanning the result set and generating a simple pixel array. Creating a new Bitmap; and then you pass that array into your new bitmaps' setPixels function.   Converting that code to JS was trivial as basically all you need to do is go to the android documentation and find out the full namespace for the things.  So the code Bitmap.createBitmap becomes android.graphics.Bitmap.createBitmap.  And Bitmap.Config.ARGB_8888 also gets prefixed with android,graphics. to become android,graphics.Bitmap.Config.ARGB_8888.

The last thing we do is add our enum value for the Android side to our QR_CODE source

NativeZXing.QR_CODE = NativeZXing.prototype.QR_CODE = com.google.zxing.BarcodeFormat.QR_CODE;

Again, this keeps it so that in the application you can easily just use ZXing.QR_CODE and never have to worry about the actually underlying platform value.

Creating the readme.mdandroidios
The next thing you need to do is create documentation; people need to understand how use you plugin.  If you can create a demo that is even better.  For example for this sample plugin I created a simple demo that lets you type in anything; and it will give you the QR code for it.  You can use the demo to help implement the plugin if the instructions aren't enough.

Wrapping it up
The final things you need to do is create a repo; and commit your code.   If it is public publish it to npm so that everyone else can use it.   If this is a private plugin; you can do tns plugin add /path/to/plugin to install it.   For example this plugin's repo is: https://github.com/NathanaelA/nativescript-zxing and can be installed via tns plugin add nativescript-zxing.

If you have any ideas on future blog posts; please feel free to comment.