NativeScript for Capacitor v2 released
With NativeScript for Capacitor 2.0, you can bring extensive versatility to your mobile developments including the ability to use NativeScript plugins from Capacitor.
With @nativescript/capacitor 2.0 comes more maturity with advancements including:
- Ability to use NativeScript plugins from Capacitor
- Ability to use @nativescript/core from Capacitor
- Fast startup time (~ < 20ms)
- Using v8 engine for both iOS and Android
Last year we introduced v1 which brought the ability to take advantage of NativeScript from Capacitor for the very first time and we continue to be inspired by the effective solutions it makes possible.
Broadening Capacitor options
With the ability to utilize NativeScript plugins from Capacitor, the community has more options to solve development challenges.
Let's take for example a Capacitor Plugin Request for Zip handling found here.
You may come across a plugin which has support for one platform but perhaps not another. In this case, a skilled contributor has provided an Android zip plugin here however it does not currently support iOS.
If you are familiar with Swift and Objective C, you may be able to help contribute to that plugin to add iOS support but what if you're not?
Let's consider you are working on a mobile project under a tight deadline and you need Zip handling support for iOS right now.
Using @nativescript/zip with Capacitor
By installing @nativescript/capacitor following the docs here you can now use various NativeScript plugins such as:
It supports iOS and Android in addition to even supporting password protected zip/unzip! 👀
What's neat about the ability to use NativeScript plugins in your Capacitor projects is you can use only what you need. You could use capacitor-zip for Android and you could also use @nativescript/zip for iOS.
@nativescript/capacitor gives you an isolated development area, src/nativescript, alongside your Ionic codebase only active when Capacitor is running. It also isolates NativeScript dependencies for clean architectural control and organization.
- Install NativeScript plugin:
cd src/nativescript
npm install @nativescript/zip
- Modify
src/native-custom.d.tsto contain the strongly typed utility you want to use from Ionic. This file helps you maintain a strongly typed interface to any custom NativeScript utilties you expose to your Ionic codebase.
/**
* Define your own custom strongly typed native helpers here.
*/
export interface ZipOptions {
directory: string;
archive?: string;
unzip?: boolean;
}
export interface nativeCustom {
// example provided with every install
openNativeModalView(): void;
/*
* Added for our new zip/unzip abilities!
*/
fileZip(options: ZipOptions): void;
}
-
Add a new file for our zip features:
src/nativescript/examples/zip.ts -
Import into
src/nativescript/index.ts(the NativeScript entry point):
/**
* Zip/Unzip handling
*/
import './examples/zip';
- Implement your new utility method in
src/nativescript/examples/zip.ts:
import { Zip } from '@nativescript/zip';
import { path, knownFolders } from '@nativescript/core';
import { ZipOptions } from '../../native-custom';
native.fileZip = function (options: ZipOptions) {
const directory = path.join(knownFolders.documents().path, options.directory);
const archive = path.join(knownFolders.temp().path, options.archive);
if (options.unzip) {
console.log('Unzipping archive:', archive);
console.log('Into folder:', directory);
Zip.unzip({
directory,
archive,
onProgress: (progress) => {
console.log('unzip progress:', progress);
},
}).then((filePath) => {
console.log('Unzipped files are here:', filePath);
});
} else {
console.log('Zipping directory:', directory);
console.log('Into archive:', archive);
Zip.zip({
directory,
archive,
onProgress: (progress) => {
console.log('zip progress:', progress);
},
}).then((filePath) => {
console.log('Zipped file is here:', filePath);
});
}
};
- Use in your Ionic codebase, for example:
src/app/explore-container.component.ts:
import { native } from '@nativescript/capacitor';
// ...
export class ExploreContainerComponent {
fileZip(unzip?: boolean) {
const directory = 'assets';
const archive = 'assets.zip';
if (unzip) {
native.fileUnzip({
directory,
archive,
});
} else {
native.fileZip({
directory,
archive,
});
}
}
}
- Bind to your view for user interaction:
<div id="container">
<p><a (click)="fileZip()">Zip File</a></p>
<p><a (click)="fileZip(true)">Unzip Files</a></p>
</div>
This shows how you can take advantage of utilities within @nativescript/core itself alongside anything you need.
Build and Run
For any NativeScript plugin you use, there can be iOS or Android dependencies associated with them. You can find out by opening any node_modules package to see if a platforms folder exists. Capacitor also needs to know about these dependencies.
With @nativescript/zip we can see them, for example in VS Code, with the following:
code src/nativescript/node_modules/@nativescript/zip
You will see contents, in part, as follows:
platforms
android
include.gradle
ios
Podfile
index.android.js
index.d.ts
index.ios.js
The compiled index.{android,ios}.js files are the implementation and the platforms folder specifies the native dependencies for each applicable platform. Opening platforms/ios/Podfile reveals:
pod 'SSZipArchive', '~> 2.4.3'
That is the iOS Cocoapod that @nativescript/zip uses.
Open ios/App/Podfile and let Capacitor's iOS build use it as well:
def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'NativescriptCapacitor', :path => '../../node_modules/@nativescript/capacitor'
end
target 'App' do
capacitor_pods
# Add your Pods here
# NativeScript
pod 'NativeScript'
pod 'NativeScriptUI'
# Zip/Unzip
pod 'SSZipArchive', '~> 2.4.3'
end
We can now prepare our build for Capacitor with:
yarn build:mobile
This will build your web app followed by bundling your src/nativescript in isolation.
You now have fully operational zip/unzip handling:
ionic cap run ios -l --external
Developer Notes
Right now with v2, when using NativeScript plugins with native dependencies (if they include a platforms/ios or platforms/android folder), you can add them manually to Capacitor Podfile (for iOS) or gradle (for Android).
In future versions, these will be added automatically.
There are a lot of features inside @nativescript/core and we have only tested a few with Capacitor at this time but feel free to experiment!
Example: Create a new file and open it
This shows using @nativescript/core file APIs to create a file and open it:
import { File, Utils, knownFolders, path } from '@nativescript/core';
native.createAndOpenFile = function (
content: string,
filename = 'new-file.txt'
) {
const newFile = File.fromPath(
path.join(knownFolders.documents().path, 'assets', filename)
);
newFile.writeTextSync(content, (err) => {
if (err) {
console.log('err:', err);
return;
}
});
Utils.openFile(newFile.path, 'File creation from {N} for Capacitor.');
};
Example: Ionic/Capacitor <--> NativeScript Event Communication
When needing to communicate events back and forth between Ionic/Capacitor and your NativeScript utilities you can use:
notifyEvent: (name: string, data?: any) => void: Notify event name with optional data.onEvent: (name: string, callback: Function) => void: Listen to event name with callback.removeEvent: (name: string, callback?: Function) => void: Remove event listeners.
For example using the zip example above you can use notifyEvent in your NativeScript utilities to emit events:
src/nativescript/examples/zip.ts
// ...
import { notifyEvent } from "@nativescript/capacitor/bridge";
native.fileZip = function (options: ZipOptions) {
// ...
Zip.zip({
directory,
archive,
onProgress: (progress) => {
notifyEvent('zipProgress', progress);
},
}).then((filePath) => {
notifyEvent('zipComplete', filePath);
});
}
};
You can then listen to those events in your Ionic components:
src/app/explore-container.component.ts:
import { native } from '@nativescript/capacitor';
// ...
export class ExploreContainerComponent implements OnInit {
ngOnInit() {
native.onEvent('zipComplete', (filepath) => {
console.log('ionic zip complete:', filepath);
});
native.onEvent('zipProgress', (progress) => {
console.log('ionic zip progress:', progress);
});
}
}
OpenJS Presentation and Other Video Learning
Using NativeScript with Capacitor can be further explored from these additional resources:
-
Presentation from OpenJS World 2021:
https://www.youtube.com/watch?v=OInjFvniccU
- Episode BLS035 provided by beeman.dev:
https://www.youtube.com/watch?v=AHcL_UbnnPY
Help shape the future
You can contribute in a number of helpful ways:
Celebrate the wonders and joys of JavaScript development with us anytime.