Monthly Archives: February 2016

NativeScript/JavaScript Tip: Debugging

Once thing I was made aware of today was that not everyone knows the magic "debugger;" command.   I suppose this makes sense; I rarely see it mentioned, but it is a very useful debugging command in the JavaScript world.

The "debugger;" command is used to cause the application to stop and enter the debugger at that point.   This works in Node.js, the browsers, and even in NativeScript!    In a browser the developer tools must be open; if your debugger tools are closed; it will ignore it.     In node, a debugger must already be attached or it will also ignore it.

In NativeScript it will actually halt the program and WAIT until a debugger is attached!   So don't release your code

So pretend my code in main-page.js is

function pageLoaded(args) {
var page = args.object;
debugger;
// do something with the page object.
}

You can then start the application on the device; and it will automatically stop right at that debugger; statement.   Then at the command line type: tns run android --start and you will be in the debugger right at that line.

NativeScript: Announcing {N} plugin tracking site

If you are like me occasionally you have to find a plugin and you go and check the npmjs.com site and do a search for NativeScript and then peruse a ton of entries; some relevant and some not so much.

Well, last night as I was finally working on updating my manually done plugin list (http://github.com/nathanaela/nativescript-plugins) ; I realized that the number of plugins was just getting to be too great for me to now be manually tracking them all.

So I set out to create something that could automate everything; I found a site/project called react.parts that was open source.  I quickly downloaded the source and glanced through it and promptly borrowed the data updater component.   I made a huge number of changes to the updater, some was just fixing some bugs and some was that I needed totally different fields for my purpose.    I am happy to announce today it runs on one of my servers every night getting and building the dataset for the all new NativeScript plugin site:

http://plugins.nativescript.rocks

The site as of today, Feb 18, 2016, the site lists 86 different plugins, my old manual list only had 45.   As the authors fill in data in the plugins, the data will automatically be updated and added.

We have a total of 33 different authors making NativeScript plugins!   Not bad for less than a year, and Eddy Verbruggen has the most plugins; at a count of 12 of them!  Wow, way to go Eddy!

For you plugin authors you need to make sure you have in your main package.json, the following items to get listed properly.   Some of these items if missing will be considered a minor issue; others will cause your plugin to NOT show up.  At this time you MUST have a link to the github repo that hosts it, you also must have either "nativescript" or "{N}" in your keywords.

If you want the Windows, iOS or Android icon to show up on your plugin, you need to use one of those key words also in your "keywords" OR you need to make sure you have them in your nativescript.platforms object.

Please make sure you include a version, and a license field; this is very helpful for people to quickly see in the list.  And example of the fields is what I use for my nativescript-zxing plugin.

{
  "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"
}

Please note, it updates the data nightly, so if you submit changes; and you don't see it show up in 24 hours; ping me and I'll check into what is going on...

NativeScript: Upgrading to v1.60

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.6.0

Some of the new features that I'm looking forward to trying out is new percentage(%) width/height code.   This should allow us to build even better screens.  And the massively upgraded CSS selector code which now allows CSS selectors like we use on the web.

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.6.0"

Again a big Kudos for the teams involved in making the updated from v1.3 onward so seamless; if you look at my prior upgrade posts you can see how much EASIER it is to upgrade now.

Tow Gotcha's on Android: when you convert to v1.6.0 (I assume they will fix it in 1.6.1), if you get a "Unhandled Exception -- Java.lang.RuntimeException: Unable to create application" when your app starts.  The easy solution for this that involves fixing your app.js file; as you probably have something attempting to get the application context.   The simple solution is to rewrite your app.js file to be:

var application = require("application");
if (global.android) {
    application.start({moduleName: "main-page"});
}

// All your custom initialization code 
// including any additional require statements...

if (!global.android) {
    application.start({moduleName: "main-page"});
}

Second gotcha, DO NOT USE clearHistory: true in any of your navigation calls, this will corrupt the navigation and cause some majorly WEIRD issues.

NativeScript: Tip - access a related view of a GridView/ListView/Repeater

I was asked earlier this week about how to access a related label when you click on a button or other object in the list of a ListView/GridView/Repeater. Since it took me a little while to figure this out for my own project a couple weeks ago and since someone else ran into this issue also, I'm going to post about it.

Pretend our template is such:

<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
 <ListView items="{{items}}">
  <ListView.itemTemplate>
   <StackLayout>
    <Label id="wow" text="{{text}}"/>
    <Button text="Tap" tap="onTap"/>
   </StackLayout>
  </ListView.itemTemplate>
 </ListView>
 </Page>

The code would be:
exports.pageLoaded = function(args) {
    var page = args.object;
    // Set our Record Set Data up.  
    var data = [{text: "One", color: "#FF0000"},
                {text: "Two", color: "#00FF00"},
                {text: "Three", color: "#0000FF"}];
    page.bindingContext = {items: data};
};

exports.onTap  = function(args) {
    // Find the Parent StackLayout
    var stackLayoutContainer = args.object.parent;

    // Disable button
    args.object.isEnabled = false;

    // Find the "Label" Child inside the StackLayout
    var label = stackLayoutContainer.getViewById('wow');    

    // Look at our Specific Record 
    var dataRecord = args.object.bindingContext;

    // Set the Label color to our Records color...
    label.backgroundColor = dataRecord.color;
};

So in this example; I'm showing you two cool things about the args that get sent to the onTap function inside a ListView.   The first item, is args.object -- this is the actual button.  So if you wanted to disable the button you could something like args.object.isEnabled = false; and it would disable just that specific button.  However, items in the view tree have a parent.   In our Declarative UI XML you can see that the Button is a child of the StackLayout, then that means the StackLayout is the parent.  So once we have the parent object, we just search its children for the child (label) we want.    Once we have the label we can do whatever we want with it.

The next thing I'm showing you is that in addition to the Button having a parent property, in this case the Button will also have a bindingContext property.  The bindingContext in this case is the single record that was used in the creation of this specific view object (i.e. Button in this case).  So for the first Button, it would have the full "One" record.  The second Button has the "Two" record and the final Button has the "Three" record.  You can use this information to be able to do just about anything from the Button since you now know which record this tap event is now related to.   Instead of a Button, we could have used a Image, Label, or any other view object.   The args passed to the tap event would contain the same information.blog-listview-sample

As you can see in this simple sample, by clicking the second button; it found the "Two" label, changed the color to the color that we set in the "Two" record; and also disabled the tap button.    If you were to tap the Third button, it would change that label to be blue, since the third record has color: "#0000FF" as its color.

NativeScript: iOS xCode 7.2+ Code signing fix!

For the last couple months since xCode 7.2 was released, those poor iOS developers who upgraded to 7.2 have felt much pain if they installed any Cocoapods. If you didn't use any PODs you were fine.  But the minute you used a plugin that has a POD; you were in for a world of hurt.  And this error: CodeSign error: entitlements are required for product type 'Application' in SDK 'Simulator - iOS 9.2'. Your Xcode installation may be damaged.  Was our only clue to what was wrong, not very helpful since Simulator apps aren't supposed to be signed.

The solutions that I handed out was to either to de-install and downgrade to 7.1 or to  build the app inside of the xCode environment.  Neither were great solutions.

I saw the solution appear a couple days ago in the issues; and finally had time to upgrade my environment back up to 7.2.1 to test and verify before I spread the good news.

I can't take credit for the fix, that goes to Ivan & Dimitar at Telerik who figured out why those using xCode 7.2+ could no longer use the TNS command line to build our applications.   The fixes will be showing up in the new v1.6 which should be released any day now; but in the meantime I figured I would document the fix so that you can apply it to your projects now.  And unless you are planning on uninstalling the iOS runtimes and install them again in v1.6; you will still have to manually apply this fix to any existing projects.

xcode-Fix-1So lets say your app is named: MyAwesomeApp.   You need to navigate to your MyAwesomeApp/ platforms / ios / MyAwesomeApp / folder and then edit the build.xcconfig file. In the picture above the app is called crossCommunicator; so you will see that the path for the file for my app is crossCommunicator / platforms / ios / crossCommunicator / build.xcconfig.

Open that file up and then you should see something like this:

xcode-Fix-2You see that line that says:
CODE_SIGN_IDENTITY = iPhone Developer?
Comment it out, so that it now says:
// CODE_SIGN_IDENTITY = iPhone Developer

xcode-Fix-3

Save the file, and you are all set to go!   You can now use xCode 7.2+ and Cocoapods fine!

 

NativeScript: Keeping your AndroidManifest.xml easily editable and under version control.

So here I was again minding my own business on the forums again, and Ben posted he had been attempting to use this new feature of v1.5.x of NativeScript and it was failing.  I responded it didn't work like that.   Thankfully he was persistent and ignored my wrong response, and linked to the github issue a second time where they discuss the new feature.   Him, being persistent despite me telling him it doesn't work that way; is why we now have a way to make it work!   So thank you Ben!

So I went and looked at the new feature and found that by default it doesn't work as a normal person would expect.    It does exactly what I expected and why I said it doesn't work.    However, I decided to see if I could make it work the way any sane person would want it to and guess what, I have a method to make this work perfectly.

To make this work properly;  you need NativeScript v1.5.1 or later; so type tns --version and make sure you are running v1.5.1 and later, if not upgrade.

WARNING: changing things in your platforms folder can completely break your build; and if you totally break your build you can do a tns platform remove android and then a tns platform add android to reset it.

First, you will need to navigate to your /platforms/android/src/main and copy the AndroidManifest.xml file to your /app/App_Resources/Android/ folder.   This is going to be your primary manifest and the one you will edit to your hearts desire.  Make sure you COPY just your app manifest.

Next you will need to edit the /platforms/android/src/main/AndroidManifest.xml and basically deleted everything in it.   This file should end up looking like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest  xmlns:android="http://schemas.android.com/apk/res/android"
package="YOUR_APP_PACKAGE" >
</manifest>

Do not copy the above as is; you need to make sure the "package" property contains your app package name, which is why I recommend you edit the one in their as it already has your app package in it.  If you copy the example above, it has YOUR_APP_PACKAGE which is an invalid package name.

Because the manifests are merged; and since the package name doesn't change the merging system is able to merge everything in your brand new App_Resources/Android/AndroidManifest.xml into the original AndroidManifest.xml file without any conflicts!