Apps Panel SDK Installation Guide for Expo

To include the Apps Panel SDK in an existing project, you need to follow this steps:

Create a local expo module using this command

npx create-expo-module@latest --local

This command will generate a module folder for iOS and Android

See => Get Started

IOS

  • Change the generated Podspec file in {yourModule/ios} to include the Apps Panel SDK
s.dependency 'AppsPanelSDKv5'
  • Create an AppDelegate Subscriber class to modify lifecycle events and initialize the SDK as well as the PushNotification Manager.
import ExpoModulesCore
import AppsPanelSDK

public class APSDKSubscriber: ExpoAppDelegateSubscriber {
  required public init() {}

  public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    try? AppsPanel.shared.configure(
      withAppName: "appName",
      appKey: "appKey",
      privateKey: "privateKey"
    )
    try? AppsPanel.shared.startSession()

    PushNotificationManager.shared.registerForPushNotifications(application: application)
    PushNotificationManager.shared.checkReceivedNotification(
      launchOptions: launchOptions,
      state: application.applicationState
    )

    return true
  }

  public func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
		PushNotificationManager.shared.registerDevice(token: deviceToken)
	}

}
  • You also need to reference your Subscriber Class in the "expo-module.config.json" file of your Native Module like so:
"apple": {
    "modules": [
      "APSDKModule"
    ],
    "appDelegateSubscribers": [
      "APSDKSubscriber"
    ]
  },

More information => iOS AppDelegate Subscribers Documentation

Android

  • To include the AppsPanel SDK in the android projet, we need to add the maven repository in the "expo-build-properties" of the "app.json" file under "plugins" sections

[
        "expo-build-properties",
        {
          "android": {
            "extraMavenRepos": [
              {
                "url": "https://repository.appspanel.com/repository/apnl-internal-android-sdk/",
                "credentials": {
                  "username": "guest-internal",
                  "password":  "YECyaNuqPCSt85t9Pdhh"
                }
              }
            ],
            "enableJetifier": true
          },
          "ios": {
            "deploymentTarget": "15.1"
          }
        }
      ]
  • Create a Application LifecycleListener file in the android folder to modify lifecycle events and initialize the SDK

( You can also create a Activity LifecyleListener if needed)

package APSDK

import com.appspanel.APSDK
import com.appspanel.manager.conf.APLocalConfiguration
import android.app.Application
import expo.modules.core.interfaces.ApplicationLifecycleListener
import com.appspanel.APSDKInterface

class APSDKApplicationLifecycleListener : ApplicationLifecycleListener, APSDKInterface {
  override fun onCreate(application: Application) {
    // Your setup code in `Application.onCreate`.
    APSDK.install(
      application,
      APLocalConfiguration(
"appName",
"appKey",
"privateKey"
        )
    )
  }
}
  • Create a package file to include the file above:
package APSDK

import android.content.Context
import expo.modules.core.interfaces.ApplicationLifecycleListener
import expo.modules.core.interfaces.Package

class APSDKPackage : Package {
  override fun createApplicationLifecycleListeners(context: Context): List<ApplicationLifecycleListener> {
    return listOf(APSDKApplicationLifecycleListener())
  }
}

More information => Android Lifecycle Listeners Documentation

Extra Configuration

Since Expo's ios and android folder are generated and iOS Podfile modifications are needed to make the Apps Panel SDK work, we need to use config plugins to modify those files.
Here's an example on how to add the "use_frameworks!" line to the Podfile as well as the post install script

// withModifiedPodfile.js
const { withDangerousMod } = require('@expo/config-plugins');
const { readFileSync, writeFileSync } = require('fs');
const path = require('path');

/**
 * Config plugin to modify the generated Podfile by:
 * 1. Adding "use_frameworks!" under the target declaration
 * 2. Adding BUILD_LIBRARY_FOR_DISTRIBUTION setting in post_install script
 */
const withModifiedPodfile = (config) => {
  return withDangerousMod(config, [
    'ios',
    async (config) => {
      const podfilePath = path.join(config.modRequest.platformProjectRoot, 'Podfile');
      
      // Read the generated Podfile
      let podfileContent = readFileSync(podfilePath, 'utf8');
      
      // Add "use_frameworks!" under the target declaration
      // Look for the target pattern and add our line after it
      const targetPattern = /target ['"].*['"] do/;
      podfileContent = podfileContent.replace(
        targetPattern,
        (match) => `${match}\n  use_frameworks!`
      );
      
      // Add BUILD_LIBRARY_FOR_DISTRIBUTION setting in post_install script
      const buildLibraryForDistributionBlock = `
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
    end
  end`;
      
      // Check if post_install hook already exists
      if (podfileContent.includes('post_install do |installer|')) {
        // Post_install exists, inject our code at the beginning of the block
        podfileContent = podfileContent.replace(
          /post_install do \|installer\|([\s\S]*?)end/m,
          (match, postInstallContent) => {
            if (match.includes("BUILD_LIBRARY_FOR_DISTRIBUTION")) {
              // The setting is already there, don't duplicate it
              return match;
            }
            return `post_install do |installer|${buildLibraryForDistributionBlock}${postInstallContent}end`;
          }
        );
      } else {
        // No post_install hook, add one at the end of the file
        podfileContent = `${podfileContent.trim()}\n\npost_install do |installer|${buildLibraryForDistributionBlock}\nend\n`;
      }
      
      // Write the modified content back to the Podfile
      writeFileSync(podfilePath, podfileContent);
      
      return config;
    },
  ]);
};

module.exports = withModifiedPodfile;

To include those modifications, we need to add this config plugin to the "plugins" section in the "app.json" file like so:

"plugins": [
      "./plugins/withModifiedPodfile.js", ---> HERE
      [
        "expo-build-properties",
        {
          "android": {
            "extraMavenRepos": [
              {
                "url": "https://repository.appspanel.com/repository/apnl-internal-android-sdk/",
                "credentials": {
                  "username": "guest-internal",
                  "password":  "YECyaNuqPCSt85t9Pdhh"
                }
              }
            ],
            "enableJetifier": true
          },
          "ios": {
            "deploymentTarget": "15.1"
          }
        }
      ]
    ]

The final step is to run the prebuild command to generate the ios and android folders with the modifications needed:

npx expo prebuild

You should now be able to use the Apps Panel SDK in your expo Project 🎉