Category Archives: Tips

NativeScript: Debugging the Android Build Process

I've seen this error myself a couple times and it appears that several others have ran into it..   You type something like tns run android or tns build android and it gives you an error about some process failing to build -1 error and to try a --stacktrace to see more info...  Not entirely helpful.   How do you do a --stacktrace?

So let me tell you how to actually do a --stacktrace; the magic is simple, but not obvious.

You need to do the following:

cd platforms/android
./gradlew buildapk --stacktrace

Pretty simple once you know it...   This is what TNS uses to actually do the building part of the process; so when it fails; you need to manually run the process with the --stacktrace parameter.  This will NORMALLY give you why it failed; however there are cases where it doesn't.   So in those cases you try this command next:

./gradlew buildapk --stacktrace --info

And if that fails; then you try the really realllllllly reallllllllllly verbose output command:

./gradlew buildapk --stacktrace --debug > somefile.txt

Then open up the text file in some editor that can handle 5 megs of text and search for the first occurrence of "failed" will typically give you why it failed....

One interesting issue that I ran into the other day helping a buddy of mine...   TNS seems to assume that anything not listed as a DevDependancy is a Dependancy; this can cause serious issues sometimes with things that actually should NOT be compiled into the app.   TNS builds a module using gyp; and gyp requires tar and tar-pack.  The authors of tar & tar-pack decided that the npm modules should have tests included in them (what????  Are you crazy?) and these tests have .tgz and .gz files in it.   Unfortunately these .tgz and .gz files will cause the android tools to fail in a lot of cases when it attempts to process them.

So there is two ways to solve this issue:

  1. Add tar & tar-pack to your dev-dependancies.
  2. Manually enter your node_modules folder; and find tar/tar-pack and then delete the test folders.

In my opinion adding those two modules to your dev-dependancies simplifies things and then you don't forget about them at some later point if you have to reinstall your modules...

NativeScript: Version 2.2.0 released

ns-2.2.0For those living in a dungeon hacking out code; guess what was released by those fine wizards at Telerik today!     Yes, you got it - v2.2.0 of NativeScript is now available!   Upgrade Instructions below.

As usual; if you run into any issues I will be putting any common issues at the bottom of this post as I and others run into them....

New or Fixed Features:

  • Android now properly supports some the of the Java classes that were broken in 2.1 (Major)
  • Nested Bindables
  • Letter Spacing is now all in EM Units (CSS: letter-spacing)
  • CSS supports new properties, more selectors and even pseudo selectors (Major)
  • Android Launch Screen Support
  • Observable's are now auto-nesting (this can cause a breaking changes -- see known issues below)

A Lot of other smaller bug fixes and enhancements went into place; unfortunately the really big feature for 2.2.0 has slipped -- threads.   It was bigger than a single point release could handle; I've seen progress on both Android and iOS on this front; so I have high hopes it will make it in 2.3.0...

Upgrading:

First of all to upgrade is done is a couple steps:
> npm install -g nativescript
> npm install tns-core-modules@latest --save

For Android:
> tns platform remove android
> tns platform add android

For iOS
> tns platform remove ios
> tns platform add ios

Then you can type tns info and verify that everything says v2.2.x

 

Common Issues

Nested Observables might throw an error

(iOS) TypeError: Cannot set property 'disableNotifications' of undefined
(Android) TypeError: undefined is not an object

If you have objects like

var x = new Observable({
y: new ObservableArray([])
});

This will probably throw the above error; eliminate the nesting; and make the structure like this:

var x = new Observable({
y: []
});

Github issue: https://github.com/NativeScript/NativeScript/issues/2457

x86_64 bit Emulator on iOS might crash on code that is fine.

Error:

Service exited due to signal: Segmentation fault: 11

Solution: Switch to a 32bit emulator like the iPhone 4s.

Github Issue: https://github.com/NativeScript/ios-runtime/issues/622

 

Angular 2 cssClasses Incompatibility

ORIGINAL EXCEPTION: TypeError: _this.cssClasses(...).set is not a function

You need to upgrade your NativeScript-Angular version to the latest version; the older version which worked with v2.1.0 of NativeScript is incompatible with v2.2.0. You should be able to do a

> npm install nativescipt-angular@latest --save

 

NativeScript: Patreon Posts & Plugins

For those who are unaware; I've started doing paid content; see my post on "Why Patreon" to see the reasons.   I'm going to attempt to keep this post updated with plugins and posts that are available to those who are my patreon supporters.

Posts:

 

Plugins:

 

NativeScript, TypeScript and accessing native Android runtimes

When you are trying to access any of the native android platform using TypeScript, TS will complain about the root name --
TS2304: Cannot find name 'zzzz' at line yyyy

TypeScript is unaware that those variables exist and are actually global in scope; so to make TypeScript happy; in your code you will want to do something like this:

declare var android: any;
declare var com: any;
declare var java: any;

This will tell TypeScript that these are global, so it will no longer throw an error when you try to access any classes that start with android, java, or com. If you are accessing any other classes that Android publishes, you can also use the same technique: declare var zzzz: any;

Small update; Josh mentioned it via twitter about installing the tns-platform-declarations.  I'm not sure why I didn't post this here also -- so I'm updating the post a tad -- installing the tns-platform-declarations will get you intellisense for the android & ios platforms.  It is well worth the download if you are using native ios or android calls.

Downgrading NativeScript

You might have decided to be an early adopter of the awesome new version of NativeScript release and then unfortunately do to some bug regretted that choice.   Well here is how to easily downgrade back to a version you prefer.

First of all, you normally do NOT need to downgrade the actual TNS / nativescript command, it is normally backwards compatible.  However if you do need to downgrade the command line utility you need to type:

npm remove -g nativescript

and then
npm install -g nativescript@version --- where version is the version you want.

Ok, now onto the two pieces that you should do at the same time.  So lets say you want to downgrade to the latest v1.6; you change to your apps main directory and would type:
npm install tns-core-modules@1.6.2

then type for android:
tns platform remove android
tns platform add android@1.6.3

and finally if for iOS:
tns platform remove ios
tns platform add ios@1.6.0

By doing these items, you will fully downgrade your app to a prior version of NativeScript.

Please note to get the version numbers of all the releases of a particular item; you can do:

npm info tns-android versions
npm info tns-ios versions
npm info tns-core-modules versions

You typically want the latest of a point release version, so you find the latest "z" version in the x.y.z branch you are looking to install. Please note the versions 2.0.0-YYYY-MM-DD-VVV like 2.0.0-2016-05-03-553 is a alpha/beta/test releases; all these dated versions you can safely ignore them.

NativeScript 2.0

It has been a long road since I first started with the just freshly released v0.90 slightly over a year ago.   I saw a product that was brand new, raw, full of life and it offered a huge amount of potential.   I decided that even though it wasn't nearly as popular as other recently released next generation product, ReactNative; that the underlying design of NativeScript was a much better foundation.  So, I took a chance and decided to use NativeScript for all my projects.  I am very grateful for Telerik open sourcing the entire stack, it has not only allowed me to see what geniuses the entire Telerik team is, but it has eliminated any concern of using this stack for well into future.

Now with the 2.0 release ,the future for NativeScript is even brighter.  So many new features, so many existing features honed to be even better!   This is a awesome release!

Some stats; In just the common core modules, we have had over 2,500 different commits since v0.90 by 40 different authors, of which over 1/3 of the authors are totally independent developers like me.   In addition, when I started we had maybe a handful of plugins, according the the http://plugins.nativescript.rocks/ we are up to over 150 different addons of which were made by over 45 different authors.     Not bad for a open source project no one had even heard of at the beginning of March of 2015...

The newest and biggest feature being release with version 2.0 is the Angular 2 support.  Several of my fellow compatriots, Nathan Walker & T.J. VanToll and Burke Holland have created some amazing things with Angular 2.0 and NativeScript.   If you are an Angular 2 fan, check them out.

Some of the other cool brand new features in v2.0 are;

  • CSS Z-Index & RGB w/ Alpha support, Awesome!
  • Android 6 Permission support
  • Normal component properties (like orientation) can now be set via CSS
  • CSS 3 Animations, Sweet!
  • Android Widget support
  • And several dozen additional bugs and feature were implemented.

Now to install this awesome new release in four simple steps:

  1. Install the new version of the NativeScript command line
    • npm install -g nativescript
  2. Remove the existing platform
    • tns platform remove android
      AND/OR
    • tns platform remove ios
  3. Add the platform(s) you need
    • tns plaform add android
      AND/OR
    • tns platform add ios
  4. Install the common core modules
    • npm install tns-core-modules@latest --save

 

 

NativeScript: Enabling beta android v8 features

nv8One of the interesting things about the v8 engine is there is a lot of development going on behind the scenes that you can actually enable right now.  This is supported in NodeJS, Chrome, and yes even NativeScript.

Currently v8 for NativeScript 1.7 Android is running on v4.7.80 --   So because this is fairly old; a lot of the ES6 code has not been exposed to the engine.   As NativeScript adopts the newer v8 engines, most of the ES6 functionality should start becoming available by default.    However if you are inpatient, you can enable this in your own NativeScript application.  Please note; some of the functionality might work perfectly; but some of it might be very buggy; that is why it is behind feature flags.

To enable functionality; you need to open the "package.json" folder in your "app" folder; it typically will look like this:

{
  "name": "tns-template-hello-world",
  "main": "app.js",
  "version": "1.7.0",
  "author": {
    "name": "Telerik",
    "email": "support@telerik.com"
  },
  "description": "Nativescript hello-world project template",
  "license": "Apache-2.0",
  "keywords": [
    "telerik",
    "mobile",
    "nativescript",
    "{N}",
    "tns",
    "appbuilder",
    "template"
  ],
  "repository": {
    "type": "git",
    "url": "git://github.com/NativeScript/template-hello-world.git"
  },
  "bugs": {
    "url": "https://github.com/NativeScript/template-hello-world/issues"
  },
  "homepage": "https://github.com/NativeScript/template-hello-world",
  "android": {
    "v8Flags": "--expose_gc"
  },
  "readme": "ERROR: No README data found!",
  "_id": "tns-template-hello-world@1.7.0",
  "_from": "tns-template-hello-world@1.7.0"
}

Yes, this is the STOCK 1.7.0 hello world template definition.     Do you see about 5 lines up the package.json from the bottom?

"android": {
  "v8Flags": "--expose_gc"
}

Well, that is where you would add your flags; !!!WARNING!!! DO NOT REMOVE the --expose_gc if you remove it, your app will crash when NS attempts to manually do garbage collection.  So, trust me when I say, do not remove it!

So some of the flags you can add and use are:

  • --use_strict = Will force everything to be in strict mode
  • --harmony_proxies = Enable ES6 Proxy support
  • --harmony_collections = Enable ES6 Maps/Sets
  • --harmony_typeof = Enable ES6 Typeof
  • --harmony_scoping = Enable ES6 Scoping rules
  • --harmony_generators = Enabled ES6 Generators
  • --harmony_itteration = Enable ES6 for-of
  • --harmony_numeric_literals = Enables the new ES6 number constants
  • --harmony_strings = Enable new ES6 String features
  • --harmony_arrays = Enable new ES6 Array features
  • --harmony_maths = Enable new ES6 Math features

These are all Harmony / ES6 related; some of the ES6 code might already be exposed; some of the ES6 code doesn't work real well and might be incomplete.  Please note that some of these ES6 features may already be fully live in the engine.   As NS gets closer to 5.1 of the v8 the more feature will be completed and exposed by default without having to use these flags.   There are MANY other flags you can use to tune the v8 engine and disable functionality; however if you don't know how what they do and the ramifications of using them, I would not set them in any customer facing application.

So if you wanted to enable the new Array & new Typeof abilities your android section would be

"android": {
  "v8Flags": "--expose_gc --harmony_array --harmony_typeof"
}

One other word of caution; these are ONLY for Android; this does not effect the iOS or Windows runtimes.  So if you enable a feature in Android; that same code may or may not run on iOS or Windows.

NativeScript: Upgrading to v1.7.0

Since I have been posting these since the early versions of NativeScript; I figured I would continue. It has been several months since the last major upgrade and this version has all sorts of bug fixes and new goodies. The changelog is available at https://github.com/NativeScript/NativeScript/releases/tag/v1.7.0

The biggest new feature is the ability to override the Android Application and Activity class; this is huge news for those who needed to override a callback on either of these Java classes.     However their are lots of fixes and some things look a lot nicer.

1. npm install -g nativescript
if you now look at your nativescript --version you should have a nice v1.6.0 show up. You only have to do this one time.

2. npm install tns-core-modules@latest --save
What, that is it to install all the new core modules? WooHoo, so simple! Make sure you do this on EACH of your projects!

3. tns platform remove android AND/OR tns platform remove ios
Please note before you run the above commands if you have made ANY changes to the xcode project, plists or the Android manifest; you might want to back them up first, or you will have to manually make those changes again. Again this has to be done for EACH of your projects...

4. tns platform add android AND/OR tns platform add ios
This also needs to be done for each project. You can do a type package.json or cat package.json and you should see everything say "1.7.0"

 

Several of the android navigation issues are now fully fixed; however there is still one that is still outstanding.  That awesome NativeScript team is working on it and it will be fixed in the next week or so and then it will be released as a point release.

 

NativeScript: Android plugins and Windows path size issues

If your on Linux or OSX you can skip this post; it only applies to us pathetic people that prefer Windows (like me ). I do have Linux and OSX, so maybe I'm not that pathetic; but since I do prefer Windows, maybe I am.

If you don't want to read the reason this occurs but all you want is the fix; then scroll down to the fix!

Well if you see this error: Command [Some Path]\gradlew.bat failed with exit code 1 then you more than likely ran into this error if you see a lot of messages above it with "No Delegate Set" and errors.

Well to understand the issue you need to understand that this is a issue between Windows, Gradle and how NativeScript (A fix might show up by v1.8 of NativeScript) currently does Android plugins. Windows, if it supported larger path sizes; this wouldn't be an issue (which is why it works on Mac/Linux). NativeScript if it handled plugins differently might not run into this issue either. But at the current place we are at; it does so here is the crux of the issue.

1. Windows only supports 255 character path sizes (if they are not UNC or Unicode path's)

2. NativeScript scans all your plugins; any that have a platforms/android folder; it will use the include.gradle file found in that folder.  If there is NOT a include.gradle file; it will create one for you using the plugin name as the information.

3. Gradle combines all the productFlavors (which are inside the include.gradle files) into one long string.

Ok, lets look at a sample include.gradle file (this is also what is also generated for you, if it doesn't exist)

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

So lets pretend your code exists at: C:\nativescript\AwesomeProject\, so there is (32) characters. Now add platforms\android\ (18). Next add build\intermediates\res\merged\ (31) as this is where Gradle does its resource merging. So lets say you are using the Telerik NativeScript UI plugin; and lets grab one of the image names \debug\drawable-xxhdpi\someimage.png which is of course adds another 49 characters. So this means we are using 130 characters already; leaving us with 122 characters left to play with.

So if you have a plugin installed like nativescript-websockets you get 23 characters used just for a single plugin. I bet you can see where this is going. Add on the cool nativescript-telerik-ui plugin and you have another 23 characters used. Add just a couple more plugins, and yes -- you are now well over 255 character limit!

Guess what happens???    Well if you are following the story so far; you get a nice error that gradle quit with error 1.

The Fix:

Now for the good news; here is how you can continue developing!

  1. Go to your app folder and do a tns platform remove android to safely recover, you need to kill your existing android platforms folder.
  2. Go into you node_modules folder, and then you need to repeat this next set of steps for EACH of the plugins you have installed.
    • Enter that plugins platforms\android folder and edit the include.gradle -- if that folder doesn't exist then you are done and can skip this plugin.  If the folder exists but the include.gradle file doesn't exist you can choose to ignore it or create your own.  DO NOT create a platforms\android folder, if it doesn't exist. Only create a include.gradle if the plugin already has a platforms\android folder and it doesn't have a include.gradle.
    • Edit the include.gradle and make the name shorter; this is the formula that I used.   Replace nativescript with "ns", eliminate any dashes, and then use the first letter for each word in the plugin.   So "nativescript-cardview" becomes "nscv",and "nativescript-telerik-ui" becomes "nstu". So the include.gradle changes from above (nativescript-websockets) to:
      android {
          productFlavors {
              "nsws" {
                  dimension "nsws"
              }
          }
      }

      Pretty simple huh?   By shorting the name, you go from 23 character per plugin to 4 characters per plugin.   So you can now easily fit 5 plugins in the same space it used to take for 1 plugin.  Please make sure the total letters are unique -- don't have two plugins with the same name (i.e. "nsws" for nativescript-websockets and nativescript-webserver)  as the same name, make them distinct.  Having duplicate names will probably break Gradle.
  3. Do a nativescript platform add android to re-install the platform after you are all done, and then you should be good to go.

Please note this potential side effect: I have confirmation below that if you are using a plugin that requires additional permissions; this work around will unfortunately not merge the info from the plugins AndroidManifest.xml file.   With all the plugins I had, I never saw this issue; but depending on what you are doing this is something you may run into.   You have two choices to deal with this:

  1. Don't rename that specific plugin inside the include.gradle file.  This way the AndroidManifest.xml file will get merged properly.   You an afford a couple plugins to still have large names.
  2. Copy the information that you need (like permissions) from the plugins AndroidManifest and manually merge it into your master manifest located at App/App_Resources/Android/AndroidManifest.xml

The bug report so you can track this is Android/369 and based on the conversation with the NativeScript devs this should hopefully be fixed in v1.8 (but no promises).

NativeScript - Capturing the Back Button on Android

Quite frequently you want to control what happens when your user hits the back button, well this is actually pretty simple to do on Android.  I've seen this question pop up several times; so it makes good blog post fodder.

You can either do this totally globally; or on a per page basis.   Globally, you just need to add the following code to your app.js file:

Global Event Handler:

// application variable should already be included in the app.js file
// Only do this on android
if (application.android) {
  application.android.on(application.AndroidApplication.activityBackPressedEvent, backEvent);
}

// This does the work on deciding if you want to go back
// arg.cancel = true will cancel navigating back
function backEvent(args) {
   if (dontGoBack) { args.cancel = true; }
}

You just need to figure out what your criteria is to handle canceling going back.

 

Individual Page Handler:

Now I personally prefer to put the handler on each page I need it on; so it is a little bit different.

You need to have a pageLoaded and a pageUnloaded event.

// Somewhere at the top
var application = require('application');

// Somewhere in your page you need to register your handler
exports.pageLoaded = function() {
    // We only want to register the event in Android
    if (application.android) {
        application.android.on(application.AndroidApplication.activityBackPressedEvent, backEvent);
    }
};

// When we navigate away from this page, we need to de-register the handler.
exports.pageUnloaded = function() {
    // We only want to un-register the event on Android
    if (application.android) {
        application.android.off(application.AndroidApplication.activityBackPressedEvent, backEvent);
    }
};

// This does your checks to see if you want to go back
// setting cancel=true will cancel the back 
function backEvent(args) {
  if (iRefuseToGoBack) { args.cancel = true; }
}

In your page.xml your "Page" declaration should look like:
<Page xmlns="http://schemas.nativescript.org/tns.xsd"
      loaded="pageLoaded" unloaded="pageUnloaded">

You might notice in the individual page view version I register and de-register the event.  Each time the page is loaded it will register the event, if you don't de-register the event then that event handler will STILL run each time you hit the back button.  So it is very important if you are not using a global handler, to register on load, and de-register on unload.

 

Advanced Global Technique:

There is one other way to do this; I created this technique in my nativescript-orientation plugin and as I was finishing up this post I realized it could apply here and eliminates all the busy work of registering and de-registering handlers on each page but allows you per-page handlers.  I'm actually going to switch my apps to this way; because now that I wrote it -- it is my favorite way.  🙂

In your app.js file:

var frame = require('ui/frame');
if (application.android) {
    application.android.on(application.AndroidApplication.activityBackPressedEvent, backEvent);
}

function backEvent(args) {
    var currentPage = frame.topmost().currentPage;
    if (currentPage &amp;&amp; currentPage.exports &amp;&amp; typeof currentPage.exports.backEvent === "function") {
         currentPage.exports.backEvent(args);
   }   
}

Then in any page you want to control the back Event you do:
exports.backEvent = function(args) {
  if (iDontReallyWantToGoBack) { args.cancel = true; }
}

Pretty simple you only need to have a single global register; and it checks to see if the current page has a back handler which it will call if it exists.

Have fun, and now we can all stop going back.  😀