Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/NativePipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ jobs:
path: android-apk-cache
# No restore-keys: a partial-input change must rebuild. gradle autolinks from
# native_dependencies.json, so it belongs in the key.
key: android-apk-v1-${{ runner.os }}-${{ env.BUILD_TOOLS_ID }}-${{ env.NT_SHA }}-${{ hashFiles('native-template/package-lock.json', 'native-widgets/configs/e2e/native_dependencies.json', 'native-widgets/configs/e2e/config.json', 'native-widgets/configs/e2e/google-services.json', 'native-widgets/scripts/test/add-native-dependencies.js') }}
key: android-apk-v1-${{ runner.os }}-${{ env.BUILD_TOOLS_ID }}-${{ env.NT_SHA }}-${{ hashFiles('native-template/package-lock.json', 'native-widgets/configs/e2e/native_dependencies.json', 'native-widgets/configs/e2e/*.tgz', 'native-widgets/configs/e2e/config.json', 'native-widgets/configs/e2e/google-services.json', 'native-widgets/scripts/test/add-native-dependencies.js') }}
- name: "Verify restored Android APK"
shell: bash
run: |
Expand Down Expand Up @@ -789,7 +789,7 @@ jobs:
path: native-template/ios/build/Build/Products
# No restore-keys: `pod install` regenerates Podfile.lock from native_dependencies.json,
# so the lock alone is not enough.
key: ios-app-v1-${{ runner.os }}-${{ env.XCODE_ID }}-${{ env.NT_SHA }}-${{ hashFiles('native-template/package-lock.json', 'native-template/ios/Podfile', 'native-template/ios/Podfile.lock', 'native-widgets/configs/e2e/native_dependencies.json', 'native-widgets/configs/e2e/config.json', 'native-widgets/scripts/test/add-native-dependencies.js') }}
key: ios-app-v1-${{ runner.os }}-${{ env.XCODE_ID }}-${{ env.NT_SHA }}-${{ hashFiles('native-template/package-lock.json', 'native-template/ios/Podfile', 'native-template/ios/Podfile.lock', 'native-widgets/configs/e2e/native_dependencies.json', 'native-widgets/configs/e2e/*.tgz', 'native-widgets/configs/e2e/config.json', 'native-widgets/scripts/test/add-native-dependencies.js') }}
- name: "Verify restored iOS app"
shell: bash
run: |
Expand Down
Binary file added configs/e2e/mendix-native-0.5.2.tgz
Binary file not shown.
3 changes: 2 additions & 1 deletion configs/e2e/native_dependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"react-native-permissions": "5.5.1",
"react-native-webview": "13.16.1",
"@sbaiahmed1/react-native-biometrics": "0.15.0",
"react-native-sound": "0.13.0"
"react-native-sound": "0.13.0",
"mendix-native": "file:../native-widgets/configs/e2e/mendix-native-0.5.2.tgz"
}
60 changes: 59 additions & 1 deletion configs/jsactions/rollup-plugin-collect-dependencies.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export function collectDependencies({
outputDir,
widgetName,
licenseOptions = null,
copyJsModules = true
copyJsModules = true,
runtimeProvidedPackages = []
}) {
const licensePlugin = new LicensePlugin(licenseOptions);
const managedDependencies = [];
Expand Down Expand Up @@ -54,6 +55,28 @@ export function collectDependencies({
}
return null;
},
async transform(code, id) {
for (const packageName of runtimeProvidedPackages) {
const escapedPackageName = escapeRegExp(packageName);
const isRuntimeProvidedPackageRequired = new RegExp(
`require\\(["']${escapedPackageName}(?:/[^"']+)?["']\\)|from\\s+["']${escapedPackageName}(?:/[^"']+)?["']`
).test(code);

if (!isRuntimeProvidedPackageRequired) {
continue;
}

const resolvedPackagePath = await resolvePackage(packageName, dirname(id));
if (resolvedPackagePath && !managedDependencies.includes(resolvedPackagePath)) {
managedDependencies.push(resolvedPackagePath);
}
if (resolvedPackagePath && !dependencies.some(dependency => dependency.packagePath === resolvedPackagePath)) {
dependencies.push({ packagePath: resolvedPackagePath, isTransitive: false });
}
}

return null;
},
async generateBundle() {
if (!licenseOptions) {
return;
Expand Down Expand Up @@ -84,7 +107,13 @@ export function collectDependencies({
);

for (const dependency of managedDependencies) {
const dependencyJson = await fsExtra.readJson(join(dependency, "package.json"));
const destinationPath = join(outputDir, "node_modules", getModuleName(dependency));
if (runtimeProvidedPackages.includes(dependencyJson.name)) {
await copyRuntimeProvidedModule(dependency, destinationPath);
continue;
}

await copyJsModule(dependency, destinationPath);

const transitiveDependencies = await getTransitiveDependencies(dependency, rollupOptions.external);
Expand Down Expand Up @@ -215,10 +244,39 @@ export async function copyJsModule(moduleSourcePath, to) {
}
}

async function copyRuntimeProvidedModule(moduleSourcePath, destinationPath) {
await mkdirp(destinationPath);
cpSync(join(moduleSourcePath, "package.json"), join(destinationPath, "package.json"));

if (getModuleName(moduleSourcePath) === "mendix-native") {
for (const entryPoint of [
"file-system",
"native-modules",
"navigation-mode",
"image-picker",
"notifee",
"firebase-messaging",
"schedule-exact-alarm"
]) {
const sourcePath = join(moduleSourcePath, "lib", "module", entryPoint);
if (existsSync(sourcePath)) {
cpSync(sourcePath, join(destinationPath, "lib", "module", entryPoint), {
recursive: true,
dereference: true
});
}
}
}
}

function getModuleName(modulePath) {
return modulePath.split(/[\\/]node_modules[\\/]/).pop();
}

function escapeRegExp(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

async function writeNativeDependenciesJson(nativeDependencies, outputDir, widgetName) {
if (nativeDependencies.size === 0) {
return;
Expand Down
2 changes: 2 additions & 0 deletions configs/jsactions/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default async args => {
onlyNative: false,
outputDir: outDir,
widgetName: fileOutput,
runtimeProvidedPackages: ["mendix-native"],
licenseOptions: {
thirdParty: {
includePrivate: true,
Expand Down Expand Up @@ -143,6 +144,7 @@ export default async args => {

const nativeExternal = [
/^mendix\//,
"mendix-native",
/^react-native(\/|$)/,
/^react-native-windows(\/|$)/,
/^react-native-web(\/|$)/,
Expand Down
1 change: 1 addition & 0 deletions packages/jsActions/mobile-resources-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@sbaiahmed1/react-native-biometrics": "0.15.0",
"@swan-io/react-native-browser": "1.0.1",
"fbjs": "3.0.4",
"mendix-native": "file:../../../configs/e2e/mendix-native-0.5.2.tgz",
"mime": "3.0.0",
"react-native-blob-util": "0.24.7",
"react-native-device-info": "15.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { Big } from "big.js";
import { Alert, Linking, NativeModules, Platform } from "react-native";
import { Alert, Linking, Platform } from "react-native";
import { NativeFileSystem } from "mendix-native/file-system";
import { ImagePickerManager } from "mendix-native/image-picker";
import {
CameraOptions,
ErrorCode,
Expand Down Expand Up @@ -56,7 +58,7 @@ export async function TakePicture(
}

// V3 dropped the feature of providing an action sheet so users can decide on which action to take, camera or library.
const nativeVersionMajor = NativeModules?.ImagePickerManager?.showImagePicker ? 2 : 4;
const nativeVersionMajor = ImagePickerManager.version;
const RNPermissions = nativeVersionMajor === 4 ? (await import("react-native-permissions")).default : null;

try {
Expand Down Expand Up @@ -118,7 +120,7 @@ export async function TakePicture(

async function safeRemove(filePath: string): Promise<void> {
try {
await NativeModules.MxFileSystem.remove(filePath);
await NativeFileSystem.remove(filePath);
} catch (error) {
console.warn(`Failed to remove file at ${filePath}. Error: ${error}`);
// ignore error
Expand All @@ -127,7 +129,7 @@ export async function TakePicture(

function storeFile(imageObject: mendix.lib.MxObject, uri: string): Promise<boolean> {
return new Promise((resolve, reject) => {
NativeModules.MxFileSystem.read(uri.replace("file://", ""))
NativeFileSystem.read(uri.replace("file://", ""))
.then((nativeBlob: unknown) => {
const blob = new Blob();
Object.assign(blob, { data: nativeBlob });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { Big } from "big.js";
import { Alert, Linking, NativeModules, Platform } from "react-native";
import { Alert, Linking, Platform } from "react-native";
import { NativeFileSystem } from "mendix-native/file-system";
import { ImagePickerManager } from "mendix-native/image-picker";
import {
CameraOptions,
ErrorCode,
Expand Down Expand Up @@ -46,7 +48,6 @@ export async function TakePictureAdvanced(
maximumHeight?: Big
): Promise<mendix.lib.MxObject> {
// BEGIN USER CODE

if (!picture) {
return Promise.reject(new Error("Input parameter 'Picture' is required"));
}
Expand All @@ -62,7 +63,7 @@ export async function TakePictureAdvanced(
}

// V3 dropped the feature of providing an action sheet so users can decide on which action to take, camera or library.
const nativeVersionMajor = NativeModules?.ImagePickerManager?.showImagePicker ? 2 : 4;
const nativeVersionMajor = ImagePickerManager.version;
const RNPermissions = nativeVersionMajor === 4 ? (await import("react-native-permissions")).default : null;
const resultObject = await createMxObject("NativeMobileResources.ImageMetaData");

Expand Down Expand Up @@ -171,7 +172,7 @@ export async function TakePictureAdvanced(

async function safeRemove(filePath: string): Promise<void> {
try {
await NativeModules.MxFileSystem.remove(filePath);
await NativeFileSystem.remove(filePath);
} catch (error) {
console.warn(`Failed to remove file at ${filePath}. Error: ${error}`);
// ignore error
Expand All @@ -180,7 +181,7 @@ export async function TakePictureAdvanced(

function storeFile(imageObject: mendix.lib.MxObject, uri: string): Promise<boolean> {
return new Promise((resolve, reject) => {
NativeModules.MxFileSystem.read(uri.replace("file://", ""))
NativeFileSystem.read(uri.replace("file://", ""))
.then((nativeBlob: unknown) => {
const blob = new Blob();
Object.assign(blob, { data: nativeBlob });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { NativeModules } from "react-native";
import { NotifeeApiModule } from "mendix-native/notifee";
import notifee from "react-native-notify-kit";

// BEGIN EXTRA CODE
Expand All @@ -18,7 +18,7 @@ import notifee from "react-native-notify-kit";
export async function CancelAllScheduledNotifications(): Promise<void> {
// BEGIN USER CODE
// Documentation https://github.com/invertase/notifee
if (NativeModules && !NativeModules.NotifeeApiModule) {
if (!NotifeeApiModule.isAvailable) {
return Promise.reject(new Error("Notifee native module is not available in your app"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { NativeModules } from "react-native";
import { NotifeeApiModule } from "mendix-native/notifee";
import notifee from "react-native-notify-kit";

// BEGIN EXTRA CODE
Expand All @@ -18,7 +18,7 @@ import notifee from "react-native-notify-kit";
export async function CancelScheduledNotification(notificationId?: string): Promise<void> {
// BEGIN USER CODE
// Documentation Documentation https://github.com/invertase/notifee
if (NativeModules && !NativeModules.NotifeeApiModule) {
if (!NotifeeApiModule.isAvailable) {
return Promise.reject(new Error("Notifee native module is not available in your app"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { NativeModules } from "react-native";
import { NotifeeApiModule } from "mendix-native/notifee";
import notifee from "react-native-notify-kit";

// BEGIN EXTRA CODE
Expand All @@ -18,7 +18,7 @@ import notifee from "react-native-notify-kit";
export async function ClearAllDeliveredNotifications(): Promise<void> {
// BEGIN USER CODE
// Documentation Documentation https://github.com/invertase/notifee
if (NativeModules && !NativeModules.NotifeeApiModule) {
if (!NotifeeApiModule.isAvailable) {
return Promise.reject(new Error("Notifee native module is not available in your app"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { NativeModules, Platform } from "react-native";
import { Platform } from "react-native";
import { NotifeeApiModule } from "mendix-native/notifee";
import notifee, { AndroidChannel, AndroidImportance, Notification } from "react-native-notify-kit";

// BEGIN EXTRA CODE
Expand Down Expand Up @@ -37,7 +38,7 @@ export async function DisplayNotification(
}

// Documentation Documentation https://github.com/invertase/notifee
if (NativeModules && !NativeModules.NotifeeApiModule) {
if (!NotifeeApiModule.isAvailable) {
return Promise.reject(new Error("Notifee native module is not available in your app"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { NativeModules } from "react-native";
import { RNFBMessagingModule } from "mendix-native/firebase-messaging";
import messaging from "@react-native-firebase/messaging";

// BEGIN EXTRA CODE
Expand All @@ -19,7 +19,7 @@ export async function getPushNotificationToken(): Promise<string> {
// BEGIN USER CODE
// Documentation https://rnfirebase.io/docs/v5.x.x/messaging/reference/Messaging#getToken

if (NativeModules && !NativeModules.RNFBMessagingModule) {
if (!RNFBMessagingModule.isAvailable) {
return Promise.reject(new Error("Firebase module is not available in your app"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { NativeModules } from "react-native";
import { RNFBMessagingModule } from "mendix-native/firebase-messaging";

// BEGIN EXTRA CODE
// END EXTRA CODE
Expand All @@ -18,7 +18,6 @@ import { NativeModules } from "react-native";
export async function HasNotificationPermission(): Promise<boolean> {
// BEGIN USER CODE
// Documentation https://rnfirebase.io/docs/v5.x.x/notifications/receiving-notifications

const enum permissionStatus {
NotDetermined = -1,
Denied = 0,
Expand All @@ -28,11 +27,11 @@ export async function HasNotificationPermission(): Promise<boolean> {

const allowedAuthorizationStatuses = [permissionStatus.Authorized, permissionStatus.Provisional];

if (NativeModules && !NativeModules.RNFBMessagingModule) {
if (!RNFBMessagingModule.isAvailable) {
return Promise.reject(new Error("Firebase module is not available in your app"));
}

return NativeModules.RNFBMessagingModule.hasPermission().then((authStatus: number) => {
return RNFBMessagingModule.hasPermission().then((authStatus: number) => {
if (allowedAuthorizationStatuses.includes(authStatus)) {
return Promise.resolve(true);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { NativeModules, PermissionsAndroid, Platform } from "react-native";
import { PermissionsAndroid, Platform } from "react-native";
import { RNFBMessagingModule } from "mendix-native/firebase-messaging";
import messaging from "@react-native-firebase/messaging";

// BEGIN EXTRA CODE
Expand All @@ -20,7 +21,7 @@ export async function RequestNotificationPermission(): Promise<boolean> {
// BEGIN USER CODE
// Documentation https://rnfirebase.io/messaging/usage

if (NativeModules && !NativeModules.RNFBMessagingModule) {
if (!RNFBMessagingModule.isAvailable) {
return Promise.reject(new Error("Firebase module is not available in your app"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { Big } from "big.js";
import { NativeModules } from "react-native";
import { NotifeeApiModule } from "mendix-native/notifee";
import notifee from "react-native-notify-kit";

// BEGIN EXTRA CODE
Expand All @@ -20,7 +20,7 @@ export async function SetBadgeNumber(badgeNumber?: Big): Promise<void> {
// BEGIN USER CODE
// Documentation Documentation https://github.com/invertase/notifee

if (NativeModules && !NativeModules.NotifeeApiModule) {
if (!NotifeeApiModule.isAvailable) {
return Promise.reject(new Error("Notifee native module is not available in your app"));
}

Expand Down
Loading
Loading