Extending Application and Activity
This article describes how to create custom android.app.Application
and androidx.appcompat.app.AppCompatActivity
implementations in a NativeScript application.
Note: Demo code below is taken from the Android Extend demos for plain JavaScript, TypeScript or Angular applications.
Philosophy
Because NativeScript is a JavaScript-to-Native framework, our main goal is to make as much as possible from the underlying native platforms easy to implement in JavaScript. Initially we discussed the option where developers would write Java code to achieve some more special cases like custom androidx.appcompat.app.AppCompatActivity
implementations but then we agreed that we should explore a JavaScript approach first and only if it is not possible to fallback to native code. It turned to be pretty easy, especially with the Static Binding Generator (SBG) tool.
Overview
The SBG analyzes JavaScript files and generates the corresponding Java files (or what we call bindings). Prior to the 2.1 release, the core modules provided custom Activity
and Application
implementations but these were tightly coupled with the other logic within the modules, making custom implementations close to impossible to achieve. For 2.1 we made some refactoring, with the solely purpose to shape the modules more as a library rather than a framework. In other words - to decouple the Activity
implementation from the frame.android.ts file and to completely remove the need for a custom Application
class. With these changes, the modules can now work with custom Activity
implementations.
The modules will still need to get notified for some
Activity
events in order to work properly. These events are described in the AndroidActivityCallbacks interface.
Extending Application
The following steps are needed to create custom native android.app.Application
object and use it, instead of the default com.tns.NativeScriptApplication
one, provided in the empty project template of the Android Runtime.
-
Create a new JavaScript file in your
app
folder - name itapplication.android.js
Note the
*.android
suffix - we want this file packaged for Android only. -
Declare the extend:
-
Modify the
application
entry within theAndroidManifest.xml
file found in the<application-name>app/App_Resources/Android/
folder:<application android:name="org.myApp.Application" android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/AppTheme" >
This modification is required by the native platform; it basically tells Android that your custom
Application
class will be used as the main entry point of the application. -
In order to build the app with webpack, the extended Android application should be added as an entry to the
webpack.config.js
file.entry: { bundle: entryPath, application: "./application.android", },
In this way, the source code of
application.android.ts
is bundled separately asapplication.js
file which is loaded from the nativeApplication.java
class on launch.The
bundle.js
andvendor.js
files are not loaded early enough in the application launch. That's why the logic inapplication.android.ts
is needed to be bundled separately in order to be loaded as early as needed in the application lifecycle.Note: This approach won't work if
aplication.android.ts
requires external modules.
Extending Activity
The core modules ship with a default androidx.appcompat.app.AppCompatActivity
implementation, which ensures they alone are sufficient to bootstrap an empty NativeScript application, without forcing users to declare their custom Activity
in every project. When needed, however, users may still specify custom Activity
implementation and use it to bootstrap the application. The following code demonstrates how this can be done:
-
Create a new JavaScript file in your
app
folder - name itactivity.android.js
Note the
*.android
suffix - we want this file packaged for Android only. -
Declare the extend:
Note the
this._callbacks
property. It is automatically assigned to your extended class by theframe.setActivityCallbacks
method. It implements the AndroidActivityCallbacks interface and allows the core modules to get notified for importantActivity
events. It is mandatory to call back to the modules through this interface, to ensure their proper initialization. -
Modify the
activity
entry within theAndroidManifest.xml
file found in the<application-name>app/App_Resources/Android/
folder:<activity android:name="org.myApp.MainActivity" android:label="@string/title_activity_kimera" android:configChanges="keyboardHidden|orientation|screenSize">
-
In order to build the app with webpack, the absolute path to the file where the Android activity is extended should be added to the
appComponents
array.const appComponents = [ "tns-core-modules/ui/frame", "tns-core-modules/ui/frame/activity", resolve(__dirname, "app/activity.android.ts"), ];
In this way and with the default config, these components get in the common vendor.js chunk and are required by the
android-app-components-loader
.