
Adalo Components API Updates
Notes for Component Developers
Notes for Component DevelopersOverviewDeadlinesHow to Test on Web and NativePreview your components on the webPreview your components in Native iOS and Android buildsHelpful Hints and FAQComponent install scriptsFile referenceLinking librariesCommon Errors
Overview
We’re updating our dependencies, which means your might need to change too. Here’s what we’re moving to:
react 18.2.0
react-native 0.72.5
react-native-web 0.19.8
node 18.18.0
Deadlines
These updates will roll out to ALL Adalo Makers and Apps on October 30th.
For public components, please submit new versions for review by October 20th!
How to Test on Web and Native
The steps below assume that you have been added to the feature flags for testing on web and native. If your account doesn’t look like the screenshots below please reach out to us.
Preview your components on the web
When in the Adalo Builder, you’ll see a new button in the top toolbar. Click the “Preview (New)” button to launch a version of the Adalo Previewer with the updated version of React Native Web.

Preview your components in Native iOS and Android builds
When kicking off a new native build, on the second step of the modal below the App Request Permissions section you should see a new toggle. Turn the toggle ON to run a build with the updated version of React Native. If you need to run a build of your app on the current, production version then you can turn the toggle off.

Helpful Hints and FAQ
Make every effort to make your changes backwards compatible with our current build pipeline! This will greatly reduce the number of problems that are encountered by our Makers! If you are unable to make backwards compatible changes, then we’ll need to coordinate the release of your component updates alongside the releases of react native, react native web, and node.
We have upgraded from Node 14 to Node 18 which may present some new error messages in build logs.
- If your component relies on
node-sass
, then the version must be updated to be compatible with Node 18, which is not a backwards compatible change with Node 14: - consider pre-compiling your Sass into CSS thus avoiding the need for
node-sass
- publish a version of the component that’s compatible with Node 18 and we’ll publish it at the same time as the roll-out
The error in the build logs for this one is not immediately obvious, it will probably manifest along the lines of “not being able to find the right version of Python” which produces a very long error chain output.
- If your component relies on extra install scripts then, depending on the type script you’re using, you’ll need to include the interpreter you’re using as the first line of the file. You may see your builds fail with an error like
Error: spawn Unknown system error -8
if it’s missing: - for a Bash script (e.g. a
.sh
file) you’ll need to include#!/bin/bash
- for a Node script (e.g. a
.js
file) you’ll need to include#!/usr/bin/env node
Component install scripts
If your component relies on install scripts, e.g. if you need to make changes to native code, then please be aware that the native file structure has changed between the older and newer version of React Native.
For example, in the case of iOS, the
AppDelegate.m
file is now AppDelegate.mm
and its contents is slightly altered.We recommend initialising a fresh React Native project with the version Adalo uses with the command
npx react-native@0.72.5 init TestApp --version 0.72.5
to familiarise yourself with the project structure for each native platform.We have provided a series of “comment markers” in some of the common files to help you target the part of the file you wish to add code to, rather than relying on targeting lines of code that may change over time.
These markers will only be available in the new React Native builds
AppDelegate.mm
Target the following comment markers to…
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_IMPORTS
- add imports after the standard iOS core and React Native imports
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_START
- add code directly after the opening@implementation AppDelegate
line
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_DID_FINISH_LAUNCHING_WITH_OPTIONS
- to add code to the end of thedidFinishLaunchingWithOptions
method
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_END
- add code directly before the@end
of the AppDelegate implementation
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_IMPLEMENTATION
- add code directly after the@end
of the AppDelegate implementation
index.js
Target the following comment markers to…
-
// MARKER_REACT_NATIVE_INDEX_JS_IMPORTS
- add imports after the standard iOS/Android React Native imports
// MARKER_REACT_NATIVE_INDEX_JS_REGISTER_COMPONENTS
- add code directly after theAppRegistry.registerComponent...
method call
File reference
Some React Native libraries require small modifications to the native app configuration and occasionally the code. Below are the default contents of the files that are commonly modified.
Android
android/build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "33.0.0"
minSdkVersion = 21
compileSdkVersion = 33
targetSdkVersion = 33
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
// START ADDED MANUALLY
kotlinVersion = "1.7.0"
androidXBrowser = "1.5.0"
// END ADDED MANUALLY
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("com.google.gms:google-services:4.3.3")
}
}
allprojects {
repositories {
jcenter()
}
}
android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_ic_notification" />
</application>
</manifest>
iOS
ios/Podfile
- same as React Native 0.72.5 defaultios/AdaloApp/AppDelegate.h
#import <RCTAppDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UNUserNotificationCenter.h>
@interface AppDelegate : RCTAppDelegate <UNUserNotificationCenterDelegate>
@end
ios/AdaloApp/AppDelegate.mm
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_IMPORTS
@implementation AppDelegate
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_START
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"AdaloApp";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_DID_FINISH_LAUNCHING_WITH_OPTIONS
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
}
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_END
@end
// MARKER_REACT_NATIVE_IOS_APP_DELEGATE_IMPLEMENTATION
Linking libraries
The command
npx react-native link
is no longer available in the latest version of React Native: https://github.com/facebook/react-native/issues/34095Assuming you’re using a recent version of your dependency, it should be possible to remove any lines similar to
npx react-native link react-native-dependency
from your component install scripts.If you need to link assets as part of your component installation, the following library is considered the “modern” alternative to
react-native link
:Common Errors
<something>.removeEventListener is not a function
React Native has changed how it handles removing event listeners from some of their APIs.
For example, in the teardown of a component (e.g.
componentWillUnmount()
or the functional component equivalent), you may have had the following code:import { Component } from 'react'
import { Keyboard } from 'react-native'
class MyComponent extends Component {
// ...more component code
componentDidMount() {
Keyboard.addListener('event', this.callback)
}
componentWillUnmount() {
Keyboard.removeListener('event', this.callback)
}
}
In React 0.72.5, there is no
removeEventListener
method on some of these APIs (the Keyboard
API is one of them), but instead a remove
method that you must call on a reference to the event listener.The above code becomes:
import { Component } from 'react'
import { Keyboard } from 'react-native'
class MyComponent extends Component {
// ...more component code
keyboardEventListener = null
componentDidMount() {
this.keyboardEventListener = Keyboard.addListener('event', this.callback)
}
componentWillUnmount() {
// this maintains backwards compatibility with older React Native versions
// while the Adalo platform transitions from old to new React Native
if (
this.keyboardEventListener &&
this.keyboardEventListener.remove &&
typeof this.keyboardEventListener.remove === 'function'
) {
this.keyboardEventListener.remove()
} else {
Keyboard.removeListener('event', this.callback)
}
}
}