NativeScript and Fortnite

Isn’t that an interesting title – I wonder if you can guess how I plan on tying the two together! Can we all say Click Bait! Stay tuned, and we will show you how I combine both of these into one blog post...

Now many of you know that NativeScript is 100% open source. I can take NativeScript and build the entire stack locally on my computer and never deal with Progress again, if I were to so choose. This is awesome from the standpoint that I am not technically stuck (*1) if I need to fix some issue. Many of the technology stacks in the past you could get to a point, and then if the issue was lower in the stack you were totally stuck. In my career I’ve run into this several times; and it really sucks when you can’t fix the issue because it is a issue in a lower part of the framework where you can’t get any access to it. In this case; we have full control over everything if and when we need it, so we are is a great position moving forward if using this stack.

So, the question I have seen around; and even had myself in the past was: Since NativeScript doesn’t make any money, how can Progress possibly continue to pay to keep it going? What is their business plan to turn a profit, and when will it be cut off?

Seriously; common sense says; if a product doesn’t make money after a couple years; a company will discontinue it. How many projects has Google canned that is making money; but not making as much money as they wanted to continue it? So, if the product has no real way to make money long term; then why would they keep it?

Yes, it does have a couple minor revenue streams, like paid support; but even the paid support probably doesn’t actually fully even pay for just the support techs that do all the awesome support for NativeScript. So basically NativeScript does not make any money directly. On paper; it looks like it is probably just burning money...

So why would Progress spend so much money to continue enhancing, and maintaining it, for a product that will never actually turn a profit??? Then what are our risks as the community that they will pull the plug tomorrow when they finally figure this out???

Well rest assured; I don’t believe it will discontinued any time soon. First; I would be totally shocked if most of NativeScript development costs are not written off as a very nice tax liability (*2). Smart companies have money pits in certain area for key reasons, one of the biggest is taxes. The other interesting thing is it is not really just a normal money pit used just for tax liability reasons.

NativeScript is the Advertisement. NativeScript is not a product, in that sense to Progress – it is a significant way to get you (the developer) to use Progress services. So just like some large company might pay millions of dollars in advertising; per year to try and reach you. Progress is doing the same thing – but instead they are actually targeting it specifically at developers. Virtually every dollar of advertising is being spent on developers. Who is a large part of their market target; well us developers! So it is an extremely well targeted advertisement, much better than you can do with any adwords scheme you can find!

Changing this point of view, completely changes the entire narrative of why NativeScript exists and its continued long term viability. It is no longer just a money losing venture of Progress. It is an significant advertisement to get you to use all the other Progress services. This is a critical point to understand; as this underpins the whole reason why NativeScript should continue to exist for the foreseeable future.

Since NativeScript is very much like Fortnite (see told you I would work it in!). They hand out the awesome 100% free game. And which game company has been just raking in the money (like 2.4 BILLION in 2018 alone) from a single free game? And if anyone follows Fortnite; you will know they are constantly improving it. However, they get you on all the “extra” attached revenue streams. Yes, you can play Fortnite 100% free and never spend a dime and even continue playing all the cool game modes that keep getting released.

You can also use NativeScript, create awesome apps and never actually spend a dime with Progress. Which is actually what the majority of the community does; but all Progress needs is a very small percentage of the NativeScript users to use its payed services and NativeScript ends up causing a major profit for them.

As some examples; to show how this works… Progress owns NativeScript, and say you want someone to build you an app, who is your first stop? (Especially if you are a large company!) You might see a nifty services page on Progress’s site – you contact Progress. But they do not actually do the contract work. They actually sub-contract it out to others; and take a hefty cut for that privilege. This works well for everyone involved. Or perhaps you are a independent developer; Sidekick, cloud builds, attend the conferences? All revenue streams. Larger companies; secure data storage, chatbot, ai, etc. Progress offers many of these “addon” services; and all of them have fully working integration's with NativeScript. So any development by a enterprise class company has a large chance of starting and choosing to stay with the owners of the NativeScript stack and paying for that privilege.

In other words; Progress is brilliant – they have managed to figure out how to take the same model used for Fortnite and use it on developers. So hopefully this reassures everyone that NativeScript should have a long life ahead of it. (*3)

Well played, Progress!


Notes:

*1 – I am not stuck; in that I can fix my own copy of the code and deploy the app. This does NOT mean that Progress will take your patches and fix the master so that it is fixed in the next version(s). It just means you can fix it in your copy…

*2 - Progress is a multi-national company; so they have taxes in multiple countries – different countries have different laws; but typically losses in one business unit can be used to write off tax gains in other units. So the “paper” loss of NativeScript offsets revenues from the other parts of the company, and so it then lowers some of their tax burden in probably several countries.

*3 - I am not a employee of Progress or Telerik; nor have I ever been, so this is all based on the know facts. However, this matches all the facts to a T. So, it is my strongest belief based on all public data available; that this is why NativeScript exists and will continue to exist. It also explains why Progress was willing to continue to sink million of dollars into NativeScript; and also purchased things like Kinvey for 49 million dollars.


Please note all companies names, Logos and products are owned by their respective owners and convey no endorsement of any content or other products in this post.

NativeScript 5.4 Build Failures

People who have been using the plugins like Firebase and/or other Google services may have all of a sudden had their apps stop building with an error like this.

+ adding aar plugin dependency: .[some path].\widgets-release.aar
.[somepath].\app\src\main\AndroidManifest.xml:22:18-91 Error:
Attribute application@appComponentFactory value=(android.support.v4.app.CoreComponentFactory) from [com.android.support:support-compat:28.0.0] AndroidManifest.xml:22:18-91
is also present at [androidx.core:core:1.0.0] AndroidManifest.xml:22:18-86 value=(androidx.core.app.CoreComponentFactory).
Suggestion: add 'tools:replace="android:appComponentFactory"' to element at AndroidManifest.xml:19:5-37:19 to override.


FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':app:processDebugManifest'.
Manifest merger failed : Attribute application@appComponentFactory value=(android.support.v4.app.CoreComponentFactory) from [com.android.support:support-compat:28.0.0] AndroidManifest.xml:22:18-91
is also present at [androidx.core:core:1.0.0] AndroidManifest.xml:22:18-86 value=(androidx.core.app.CoreComponentFactory).
Suggestion: add 'tools:replace="android:appComponentFactory"' to element at AndroidManifest.xml:19:5-37:19 to override.


Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
Get more help at https://help.gradle.org
BUILD FAILED in 30s

Wonderfully helpful error message huh? Well the issue is that Google recently changed their services to use AndroidX descended components. This change has been in the wings for a while and even NativeScript has been working towards this goal (NS 6.0 will be fully AndroidX). But in the meantime unfortunately Android.* and AndroidX.* are totally incompatible.

There are two things you might have to do to solve this so that you can continue to work...

  1. You create (or modify if it exists) a file in your App/App_Resources/Android/before-plugin.gradle and add the following section:
android {
     project.ext { 
          supportVersion = "28.+"
          googlePlayServicesVersion = "16.+"
     }
} 

This will pin your app to continue using a slightly older version of the Google services which is still based on the Android library. (IMPORTANT NOTE: when you later upgrade to NativeScript 6, you will want to delete this out; because NS 6 is Android X based; and so you will want the later versions).

2. If the above doesn't fully solve the issue; you may have to do a search in your node_modules and specifically the plugins for any plugin that actually uses google services in their gradle.include files; they might be hard coded to use a "+" as the version, and you will need to change them to be also "16.+"

--- UPDATE:

I had one of my friends, Dick Smith; showed me another solution via slack this morning; instead use the app.gradle file (also located in the same spot App/App_Resources/Android/app.gradle)

dependencies {
     configurations.all {
          exclude group: 'commons-logging', module: 'commons-logging'
         resolutionStrategy.eachDependency { DependencyResolveDetails details ->
             def requested = details.requested
             if (requested.group == 'com.google.firebase') {
               details.useVersion '17.+'
             }
             if (requested.group == 'com.google.android.gms') {
                 details.useVersion '16.+'
             }
             if (requested.group == 'com.android.support' && requested.name != 'multidex') {
                 // com.android.support major version should match buildToolsVersion
                 details.useVersion '28.+'
             }           
         }
     }
 }

This will override it as Gradle looks for the pieces it needs; it runs this code and even thought the plugins gradle file might state it wants version X of something; it will change it to the version we want... (Please note the same warning applies; when you upgrade to NS 6.0 in a couple months, you will want to then either change these versions to the AndroidX versions or delete this section).

--- End Update.

Finally after you make both those changes; I highly recommend you do a "tns platform clean android" before you rebuild the app, so everything is clean..

Finally if all else fails and you aren't expecting to release your app for another couple months; you can actually upgrade to the test version of NS 6.x; this version is currently unstable and you might have other issues (and you will probably want to update to the latest 6's each day just to try and make sure you are on the most recent version...)

npm i -g nativescript@next
npm i --save tns-core-modules@next
tns platform remove android
tns platform add android@next

If @next fails, and you need to return back to a solid release you can do the following:

npm i -g nativescript@latest
npm i --save tns-core-modules@latest
tns platform remove android
tns platform add android@latest

Please note; I do NOT recommend you run @next it normally is the least stable and most buggy version of Nativescript you can run. But sometimes you have to do what you have to do to proceed. 🙂

NativeScript 5.x and HMR Issues

If you are one of the lucky people who are reading this blog article, because your app used to work! After upgrading to the latest NativeScript and enabling the new Workflow your app is now broken...

Well I have some good news... It is easy to get back to a working state.

Here is how you can revert back to using the Legacy Workflow..

First thing, you need to open the nsconfig.json file in the root of your project. This file is where this key parameter is kept.

Inside the nsconfig.json file you will see "useLegacyWorkflow": true change this to false and save the file.

Then from the CLI; do a
- tns platform clean android (if using Android)
- tns platform clean ios (if using iOS)

Then you can do a tns run android or tns run ios and be back working.

Please note; DO NOT USE --bundle or --hmr flags; as this will re-enable HMR and the only reason you are changing this flag is because HMR is already not working for you...

I would recommend you submit a bug report to the nativescript-dev-webpack github repo about your issue; so that it can be tracked. Version 6.0 of NativeScript is supposedly going to disable the Legacy Workflow mode; so it is critical they get all the data they can on what issues you have seen so they can iron them all out...

Common HMR issues with fixes:

  • Your page/css/xml/html isn't changing on the device.
    • Make sure the name of the files end with "-page". So "main-page.xml" or "cool-page.css"
  • Your extra files (like sqlite databases) aren't being synced to the device.
    • Edit your webpack.config.js file, and add them to the copy step so that they are bundled up.

Some common broken NativeScript-Core HMR issues:

  • Pure JavaScript apps (i.e. not TypeScript) do not function properly on the second screen or on the first screen if using a SideDrawer as the root view. Click/Tap/Event handlers are not assigned properly.
  • Width/Height Specific files are unused (i.e. main-page.HW600.xml doesn't work; only main-page.xml is picked up.)
  • Shared NativeScript XML files do not link up to proper event handlers. (Similar to first issue; but a different aspect)
  • Some CSS files do not seem to be tracked properly.

Upgrading to XCode 10.2

Public Service Announcement.

If you are using any iOS plugins that use Swift v3 or less; DO NOT UPGRADE to XCode 10.2. Apple in its infinite wisdom has completly removed the Swift 3 tool chain.

You can re-add the tool chain back; BUT Apples guidelines state that apps submitted must be using the built in tool chain -- so odds would be very likely that if you re-added the Swift 3 tool chain to XCode 10.2, that the app would be rejected by Apple due to its requirements.

So the safest bet is to stay at XCode 10.1 if you are using any Swift plugins...

NativeScript 5.40 Released

NativeScript 5.40 only offers a smaller number of fixes and features than usual; but is still well worth upgrading to. It will probably be the last major 5.x release. NativeScript 6.00 is on the horizon...

The most interesting update (for me) is actually the Android V8 engine has been upgraded yet again. Android engine is now on v8 v 7.4 - which offers even faster JavaScript parsing (in some cases up to 10% faster) In addition to the engine speed ups; v8 now has better memory management and much better deadcode elimination.

So just upgrading the runtimes to 5.4 should again give you a faster android app... So it is worth it just for this alone. Nothing changed on the iOS side here...

In addition the v8 v7.4 now offers support for Private class variables; an ESNext feature that is finally shipping in v8. If you are unfamiliar with this feature, this feature is needed for keeping private variables private. 😀

class CoolClass {
  iAmPublic = 1;          // .iAmPublic is public variable
  #iAmPrivate = 2;        // .#iAmPrivate is private variable

  getIAmPrivate() {
     ++this.#iAmPrivate;
  }
}

const m = new CoolClass();
console.log("I am private now equals:", m.getIAmPrivate()); // runs OK
m.#iAmPrivate = 0;  // TOTALLY FAILS!   

Unfortunately, JavaScriptCore does NOT support this feature yet and the code will fail to even parse on JSC, so don't use it in any shared code. This is an Android only feature. TypeScript will soon be adding this feature, so this should become a common way of making class fields private...

Important Depreciation Notice

In version 5.2 short imports have been depreciated; I do not know when they will no longer actually work; but basically things like require("http") are no long valid; you need to do require("tns-core-modules/http"). The primary reason for this is that webpacking requires the full path; and it has problems with short imports. Please note this now becomes more critical that you handle this; NativeScript 6.00 will be 100% webpack only; meaning that if you don't fix your code it might fail to build until you do so in NativeScript 6.

Core Modules

The core modules offers the following enhancements and fixes...

Multiple iOS components have crashing issues fixed
FormattedText crashing issue fixed

Android

Upgrade to V8 7.4.288 - which offers
- Private Class Fields
- Faster JS Parsing
- Better Dead Code Elimination
Static Binding Generator fixes and enhancements
Gradle 3.40 support.
Several memory leaks fixed
v8 Symbols exportable (for native v8 extensions)
Elevation Shadow Support

iOS

Allows compiling Swift code as part of app_resources
Minor leak fixed
Unicode crash fix
Some Metadata generation fixes

CLI

HMR is now the default app type
TNS Create Plugin fixes
Better handling of CTRL-C
CocoaPod handling improved



Updating NativeScript

To get updated; you first need to do:
npm i -g nativescript@latest

That will get you the latest version of NativeScript CLI; once you have it; do a "tns --version" and verify it prints out "5.4.x".  Then do a "tns doctor" to verify your environment is up to date and has all the newest support tools you need for a successful build.  

To update a project; you need to do the following:

Latest Runtimes:
tns platform remove android && tns platform add android@latest
tns platform remove ios && tns platform add ios@latest

Latest Core modules:
npm r tns-core-modules --save
npm i tns-core-modules@latest --save

To install Webpack & HMR support:
npm i nativescript-dev-webpack@latest --save-dev
Note: you need to have nativescript-dev-webpack as a development dependency for HMR to work.  

To install latest NativeScript Angular plugin
npm i nativescript-angular@latest --save
You will then need to install the actual angular bits; which as of this post v6 is currently supported.

The addition of all the additional analytics/tracking to the CLI reminded me; you can disable it permanently; if you value your privacy by doing:
tns usage-reporting disable && tns error-reporting disable


Known issues

NativeScript-Core replacing the root view...

Please note this to my knowledge only works with NativeScript-Core / PAN (Plain Awesome NativeScript) applications. I do not believe this will work with the Vue or Angular variations of NativeScript. There maybe another way to accomplish this with those variations, and if you know how -- please let me know and I'll update this post.

So I was minding my own business again, and I saw this question pop up in NativeScript GitHub. Take this scenario; you want to have a SideDrawer that is active on all pages.

Seems simple enough you create the /app-root.xml as this:

&lt;nsDrawer:RadSideDrawer xmlns:nsDrawer="nativescript-ui-sidedrawer"><br>    &lt;nsDrawer:RadSideDrawer.drawerContent><br>        &lt;GridLayout backgroundColor="#ffffff"><br>            &lt;Label text="Go to Cool Page" tap="page1"/><br>            &lt;Label text="Go to Another Cool Page" tap="page2"/><br>        &lt;/GridLayout><br>    &lt;/nsDrawer:RadSideDrawer.drawerContent><br>    &lt;nsDrawer:RadSideDrawer.mainContent><br>        &lt;Frame defaultPage="/pages/main/main-page">&lt;/Frame><br>    &lt;/nsDrawer:RadSideDrawer.mainContent><br>&lt;/nsDrawer:RadSideDrawer><br>

But now I need a login page... And my awesome side drawer is now active on the login page. Uh-oh -- it even has a ton of links that go to places and so we don't want that if they haven't even logged in. In fact we probably don't want them to even have access to the side drawer when not logged in...

What is the solution?

My solution, is fairly simple is you revert your code back to close to the default app-root.xml:
Your <strong>app-root.xml</strong> actually is changed to this:

<Frame defaultPage="/pages/login/login-page"/>

That is because we want the main frame of the app to load my login page; in this case my login page will force them to login if they don't already have a valid stored login token... Notice, their is no SideDrawer, because it is no longer the root.. So part one is working great, no side drawer during login...

So now how do we get our cool SideDrawer to be active on the rest of all the pages...

const Application = require('tns-core-modules/application');<br><br>function loginIsValid() {<br> <strong> Application._resetRootView("/pages/root/root");</strong><br>}<br>

Yep, look their -- there is a cool feature in the framework that allows you to REPLACE (or RESET) the root view. So by doing this, my /pages/root/root.xml file now contains the SideDrawer root layout which I displayed at the top of this post.

Notes:

My own personal applications typically are laid out in such a fashion that I have a "pages" folder, and in the "pages" folder I have each separate page js, CSS, and XML. This typically allows me to quickly find the page I want to work on.

NativeScript AndroidX support and Plugins

The next major version of NativeScript (version 6) will be switching from the android.support packages to the new androidx namespace. This will be a hard break; as you can only use the support api's or androidx api's; but not both. This is something Google has been implementing for a while; and NativeScript is getting on board to eliminate later issues and give us great support. The awesome developers at Progress have already created a fork of NativeScript; which you can install to test which uses androidx instead of using the support libraries.

Since one of my plugins is affected by the changes; I took a look into what was required to support both the current versions of NativeScript and the new upcoming version of NativeScript.

For any of you who have plugins; this code is what I basically devised.

let androidSupport=null;
if (android.support && android.support.v4) {
  androidSupport = android.support.v4;
} else if (global.androidx && global.androidx.core) {
  androidSupport = global.androidx.core;
}

Then you can use androidSupport to access the namespace, and it pretty much works the same as what you would access using android.support.v4 or the new androidx.core replacement. Because we used feature detection; this allows us to support both namespaces in the same code base.

So if you have JavaScript or TypeScript code that uses android.support.* then you can use this technique to make your plugin forwards compatible with the next major version of NativeScript while retaining support for the prior versions.

Here is a list of classses that are being moved from android support to androidx: https://developer.android.com/jetpack/androidx/migrate

VMWare Network Hickups ( sent link down event. )

I ran into this because I went to a hotel that had DHCP renew every 300 seconds, trying to download something inside the VM was getting clobbered...

If you check your syslog or kern.log and see the following entries; then I might have the solution for you:

kernel: [235397.022939] userif-3: sent link down event.
kernel: [235397.022943] userif-3: sent link up event.

Then the issue is one that when your DHCP renews it calls into the kernel with the new information; unfortunately this causes VMWare Workstation & Player (might effect other VMWare products?) to reset its network stack, even though nothing changed...

The solution after a lot of time googling different terms and trying to figure out what exactly was going on. I finally found it here (by Jan Just Keijer): https://www.nikhef.nl/~janjust/vmnet/ it was for an much older version of VMWare Player; but the solution still applies to VMWare workstation 15...

To make sure the information doesn't just disappear in the future (and so I can easily find it myself) I'm going to quote the relevant code and/or modifications I did..

Extract the /usr/lib/vmware/modules/source/vmnet-only.tar tar file, you need to modify the userif.c file. Search it for VNetUserIfSetUplinkState function and right after the variable declaration add if (!linkUp) return 0;

// Around line 966
VNetUserIfSetUplinkState(VNetPort *port, uint8 linkUp)
 {
    VNetUserIF *userIf;
    VNetJack *hubJack;
    VNet_LinkStateEvent event;
    int retval;

    /* ADD: never send link down events */   
    if (!linkUp) return 0;
    /* END Added code */
    
    ... rest of code ...

This will eliminate the linkdown events; which disconnect the internet from the VMWare network driver...

After you do that; recreate the vmnet-only.tar and replace the original. Then you can run: /usr/bin/vmware-modconfig --console --install-all

And then either
systemctl restart vmware
or
service vmware restart

If you still see " sent link down event." in your logs; then the patch wasn't applied properly.

NativeScript 5.30 Released

NativeScript 5.3 only offers a smaller number of fixes and features than usual; but is still well worth upgrading to.

The most interesting update (for me) is actually the Android V8 engine has been upgraded yet again, but this time to a version that offers some nice performance benefits. It is always nice when an upgrade will increase the speed of your app with just a rebuild of it.
In addition some awesome work has been done on the iOS engine that should also result in a speed enhancement.

So just upgrading the runtimes to 5.3 should give you a faster app...

Important Depreciation Notice

In version 5.2 short imports have been depreciated; I do not know when they will no longer actually work; but basically things like require("http") are no long valid; you need to do require("tns-core-modules/http"). The primary reason for this is that webpacking requires the full path; and it has problems with short imports.

Core Modules

The core modules offers the following enhancements and fixes...

Resource ID on Android error fixed during Navigation
Webview and TabView fixes
Icons on Tabview and ActionBar should look better
View classes now have the missing .background* Style options.

Android

Upgrade to V8 7.3.492 - which offers
- Faster Await
- Faster JS Parsing
- Faster Spread Elements
- Embeddins supported in ia32 now
NativeScript Arm64 support built in on release versions
Static Binding Generator fixes and enhancements
Gradle 3.3.2 support.

iOS

Lazy Evaluation - Performance
Many Debugger fixes

CLI

HMR is no longer considered Beta; almost all critical issues with HMR are now resolved.
Several debugger issues resolved



Updating NativeScript

To get updated; you first need to do:
npm i -g nativescript@latest

That will get you the latest version of NativeScript CLI; once you have it; do a "tns --version" and verify it prints out "5.3.x".  Then do a "tns doctor" to verify your environment is up to date and has all the newest support tools you need for a successful build.  

To update a project; you need to do the following:

Latest Runtimes:
tns platform remove android && tns platform add android@latest
tns platform remove ios && tns platform add ios@latest

Latest Core modules:
npm r tns-core-modules --save
npm i tns-core-modules@latest --save

To install Webpack & HMR support:
npm i nativescript-dev-webpack@latest --save-dev
Note: you need to have nativescript-dev-webpack as a development dependency for HMR to work.  

To install latest NativeScript Angular plugin
npm i nativescript-angular@latest --save
You will then need to install the actual angular bits; which as of this post v6 is currently supported.

The addition of all the additional analytics/tracking to the CLI reminded me; you can disable it permanently; if you value your privacy by doing:
tns usage-reporting disable && tns error-reporting disable


Known issues

  • Android Q is not supported properly; The fix is slated for 3.3.1
  • TNS frequently (for me at least) kills the build with "Error is: cp: cannot create directory " and to fix you have to reset your platforms. (This might be more plugin development related corner case)