@os1-platform/dispatch-mobile
TypeScript icon, indicating that this package has built-in type declarations

2.1.9 • Public • Published

React Native Dispatch SDK

Introduction

Dispatch SDK is an expo based SDK that is written in Typescript and some Modules in Java/Kotlin. This sdk can be used to render execution task screens on ui, maintain their states, manage mts.

Currently supports SDK>=21 (Android)

Dispatch SDK provides the following features:

  • Sync Manager: Provides Sync Manager for syncing events & Docs in background with retry functionality.

  • Execution Tasks: Provides a list of Execution Tasks inbuilt UIs which are as follows.

    • Deliver
    • Capture Input
    • Deliver Cash
    • Complete-Success
    • Complete-Failure
    • Pickup
    • Doodle
    • Form
    • Display
    • Verify Location
    • Verify Input
    • Scan
    • Image Capture
    • Init Payment
    • Process Payment
    • Complete Payment
    • Validate OTP
  • Execution Engine: Provides methods for Executing a given workflow/Job in a dispatch`

  • Firebase Cloud Messaging:Provides method for receiving Firebase Cloud Messaging

  • Async storage:Provides Async storage for storing key value pairs

  • Async Events: Support for async events triggered on start and end of every execution task except end-state tasks, as for them a summary is generated at the end of completion of workflow.

    • Format of events:

      const eventName =
        `onTaskStart:{ET_Name}` |
        `onTaskEnd:{ET_name}` |
        `onTaskBack:{ET_name}` |
        `onScan:{ET_name}` |
        `onScanRemove:{ET_name}`;
    • Usage:

      import { eventListener } from '@os1-platform/dispatch-mobile';
      eventListener.on('{eventName}', (eventData) => {
        console.log(eventData);
      });
      eventListener.remove('{eventName}');
    • Event data Payload: onTaskStart event:

        `onTaskStart:{ETCustomName}` = {
          "timestamp":"number",
          "taskId":"string",
          "etData":{
            "jobId1":{
                ...ET inputs
            },
            "jobId2":{
                ...ET inputs
            }
          }
        }

      onTaskEnd event | onTaskBack event:

        `onTaskEnd:{ETCustomName}` = {
          "timestamp": "string",
          "taskId": "string",
          "etData":{
            "jobId1":{
                "success":"boolean",
                "eventCode":"string",
                "reasonCode":"string",
                ...ET output
            },
            "jobId2":{
                "success":"boolean",
                "eventCode":"string",
                "reasonCode":"string",
                ...ET output
            }
          },
          "meta"?:{},
      }

Dispatch SDK Installation

Setup Expo (For non-expo projects only)

npx install-expo-modules

Install Dispatch SDK Package

#using npm
npm install @os1-platform/dispatch-mobile

Install these dependencies

{
  "dependencies": {
    "@apollo/client": "^3.5.6",
    "@expo-google-fonts/ibm-plex-sans": "*",
    "@foxtrotplatform/platform-coreos-mts-sdk": "^0.5.10",
    "@react-native-async-storage/async-storage": "^1.15.5",
    "@react-native-community/datetimepicker": "^3.5.2",
    "@react-native-community/netinfo": "^6.0.2",
    "@react-native-community/slider": "^4.1.7",
    "@react-native-firebase/analytics": "^14.2.2",
    "@react-native-firebase/app": "^14.2.2",
    "@react-native-firebase/crashlytics": "^14.2.2",
    "@react-native-firebase/messaging": "^14.2.2",
    "@react-native-firebase/remote-config": "^14.2.2",
    "@react-navigation/native": "^6.0.6",
    "@react-navigation/native-stack": "^6.2.5",
    "@sentry/react-native": "^3.2.13",
    "axios": "^0.24.0",
    "expo": "~47.0.13",
    "expo-barcode-scanner": "~11.4.0",
    "expo-blur": "~11.0.0",
    "expo-camera": "~13.1.0",
    "expo-file-system": "~15.1.1",
    "expo-font": "~11.0.1",
    "expo-image-manipulator": "~11.0.0",
    "expo-image-picker": "~14.1.0",
    "expo-location": "~15.0.1",
    "expo-sqlite": "~11.0.0",
    "graphql": "^16.2.0",
    "react": "^18.0.0",
    "react-native": "^0.69.5",
    "react-native-dropdown-picker": "^5.4.0",
    "react-native-get-random-values": "^1.8.0",
    "react-native-paper": "^4.9.2",
    "react-native-safe-area-context": "^3.3.2",
    "react-native-screens": "^3.9.0",
    "react-native-vector-icons": "^9.0.0"
  }
}

Async Storage Size Increase

  • Add this line in gradle.properties file for increasing storage (AsyncStorage_db_size_in_MB=10)

Changes in Android Manifest File (Android only)

android:allowBackup="false"
tools:replace="android:allowBackup"
<activity
      android:name=".MainActivity"
      android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
      android:label="@string/app_name"
      android:launchMode="singleTask"
      android:windowSoftInputMode="adjustResize"
      android:exported="true">

Add jcenter() if not added already added in the Project-level build.gradle (/build.gradle): (Android only)

buildscript {

    repositories {
        ...
        jcenter()
    }
}

allprojects {
    repositories {
        ...
        jcenter()
        ...
    }
}

Fix for Apollo GraphQL Client (metro.config.js)

Add the following changes in metro.config.js file

const { getDefaultConfig } = require('metro-config');
const { resolver: defaultResolver } = getDefaultConfig.getDefaultValues();
exports.resolver = {
  ...defaultResolver,
  sourceExts: [...defaultResolver.sourceExts, 'cjs'],
};

Dispatch SDK Usage

Init Dispatch SDK

interface EventMapping {
  eventCode: string;
  successEvent: boolean;
  description: string;
}

interface DispatchSDKConfig {
  ...previous configs
  debugLevelLog?: Boolean;
  callbacks?: {
    fetchPhoneNumbersCallback?: (sdsIds: string[]) => Promise<{ key: string; value: string[]}>;
  };
}


const fetchPhoneNumbersCallback = (ids: string[]) => {
  console.log('sds ids: ', ids);
  return {
    key: 'phoneNumber', //This key is same, what was being sent in meta as key
    value: ['8888888888'],
  };
};

import { DispatchSDKManager } from '@os1-platform/dispatch-mobile';

await DispatchSDKManager.getInstance().initDispatchSDK({
  userName: 'testuser',
  userID: 'testID',
  tenantID: tenantId,
  tenantBaseURL: 'baseURL',
  accessToken: 'accessToken',
  headers: {
    'x-user-id': 'testID',
    'x-coreos-tid': tenantId,
    'x-coreos-access': accessToken,
    'Content-Type': 'application/json',
    'x-coreos-request-id': new Date().getTime(),
    'x-coreos-userinfo': JSON.stringify({ id: 'testID' }),
  },
  // Used for Scan ET dropdown list => eventMapping: EventMapping[]
  eventMapping: [
    {
      eventCode: 'E-010',
      successEvent: true,
      description: 'Success',
    },
    {
      eventCode: 'E-011',
      successEvent: false,
      description: 'Failure',
    },
  ],
  callbacks: { fetchPhoneNumbersCallback }, // Callback to fetch mobile number based on the sds-ids passed
});

Init Execution engine

interface Job {
    id: string;
    jobRef: string;
    jobWorkflowId: string;
    status: string;
    subStatus?: string | null;
    containers: Array<Container>;
    customData: any;
    displayInfo: any;
    start: string;
    objectives: Array<Objective>;
}

interface Workflow {
    name: string;
    id: string;
    tag: IWfTag[];
    description: string;
    flows: Array<ExecutionTask>;
    expire?: boolean;
    meta?: string;
}

interface Workflows {
  [workflowId:string]: Workflow;
}

import { DispatchStateContainer } from '@os1-platform/dispatch-mobile';

/**
 * Call this function when dispatch data is fetched successfully
 * @param dispatchID
 * @param jobs
 * @param logging
 * @param maxTaskReattempt
 */

await DispatchStateContainer.getInstance().initDispatchExecutor(
  dispatchID: string,
  dispatchJobs: Job[],
  dispatchWorkflows: Workflows,
  maxTaskReattempt?: number
);

Start Objective Execution

interface sdkError {
  code: string;
  message: string;
}
// Error Handling from the calling Screen
React.useEffect(() => {
  if (route.params?.sdkError) {
    console.log(JSON.stringify(route.params.sdkError));
    Alert.alert('Error', JSON.stringify(route.params.sdkError));
  }
}, [route.params?.sdkError]);

navigation.navigate('DispatchExec', {
success: true,
initRoute: 'TaskDetail',
mergedWI: {
  mwId: route.params.moId,
  customEventsData: {},
  statusFilter: ExecutionStatus[]
},
successRoute: 'SuccessScreen',
failureRoute: 'FailureScreen',
meta: META,
});

Objective Summary Route Params

export interface ObjectiveSummary {
entityCode: string;
eventCode: string;
reasonCode: string;
reasonCodeDesc?: string;
}

// When navigating to success or failure route, following are the route params:
{
summary: {
 success?: ObjectiveSummary[];
 failure?: ObjectiveSummary[];
},
objSuccess: boolean,
}

New functions

// getObjectiveTaskList
public async getMergedObjectiveList getObjectiveTaskList(
    status: ExecutionStatus[]
  ): Promise<IObjectiveTask[]> {
    return [];
  }

// getObjectiveTaskDetails
public async getMergedObjectiveDetails getObjectiveTaskDetails(
    mwId: string,
    status: ExecutionStatus[]
  ):  Promise< (IObjectiveTask & { workflowData: StoredWorkflowInstance[] | [] }) | {} >
  {
    return [];
  }

// Inventory Data
public async getRiderInventory(): Promise<IDispatch.ItemsInRiderCustody> {
	return {}
}

Interfaces

export interface IObjectiveTask {
  id: string;
  status: ExecutionStatus;
  tags: IWfTag[];
  inputs: any;
  instanceCount: number;
  location: Location;
  contact: string[];
}

export interface StoredWorkflowInstance {
  id: string;
  mergedObjectiveId: string;
  jobId: string;
  scannableId: string;
  initialMergedObjectiveId: string;
  status: ExecutionStatus;
  jobWorkflowId: string;
  workflowId: string;
  displayInfo: any;
  cashAmount: number;
}

enum ExecutionStatus {
  READY = 'READY',
  IN_PROGRESS = 'IN_PROGRESS',
  NOT_READY = 'NOT_READY',
  COMPLETED_SUCCESS = 'COMPLETED-SUCCESS',
  COMPLETED_FAILURE = 'COMPLETED-FAILURE',
}

interface IWfTag {
  name: string;
  value: string;
}

export interface Location {
  locationId: string;
  address?: any;
  geolocation?: any;
}
export interface ItemsInRiderCustody {
  shipments: {
    totalCount: number;
    deliveredCount: number;
    pickedCount: number;
  };
  cash: {
    expectedAmount: number;
    collectedAmount: number;
  };
}

FCM

Setup (android only)

Add the Firebase Android configuration file to your app:
  • Create a firebase project (Check Firebase instructions for creating app).
  • Click Download google-services.json to obtain your Firebase Android config file (google-services.json).
  • Move your config file into the module (app-level) directory of your app.
  • To enable Firebase products in your app, add the google-services plugin to your Gradle files.
In your module (app-level) Gradle file (usually app/build.gradle), apply the Google Services Gradle plugin:
apply plugin: 'com.android.application'
// Add the following line:
apply plugin: 'com.google.gms.google-services'  // Google Services plugin

android {
  // ...
}

In your root-level (project-level) Gradle file (build.gradle), add rules to include the Google Services Gradle plugin. Check that you have Google's Maven repository, as well

buildscript {

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }

  dependencies {
    // ...

    // Add the following line:
    classpath("com.android.tools.build:gradle:7.1.1")
    classpath("com.google.gms:google-services:4.3.10")  // Google Services plugin
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  }
}

allprojects {
  // ...

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    // ...
  }
}

Get FCM Token

import {
  getFCMToken,
  requestFirebasePermissions,
} from '@os1-platform/dispatch-mobile';
//Get FCM Token
let token = await getFCMToken();

//Request Notifications permissions (ios)
// It will ask for user permissions for showing alert/notifications
let enabled = await requestFirebasePermissions();

Background FCM Messages

Register callback for receiving FCM Messages in background

Note : Call this function in the root component i.e in index.js file of the app

import { registerBackgroundHandler } from '@os1-platform/dispatch-mobile';

registerBackgroundHandler((message: object) => {
  // Handle FCM Message here
});

Foreground FCM Messages

useFcmMessage() custom hook in functional components to receive FCM Messages in Foregound
import { useFCMMessage } from '@os1-platform/dispatch-mobile';

const fcmMessage = useFCMMessage();
if (fcmMessage != null) {
  // update UI here to show the message
}

OR

extend FCM Base class in case of class components
import { FCM } from '@os1-platform/dispatch-mobile';

class ClassComponent extends FCM {
  //implement these methods
  handleFcmMessage(remoteMessage: object): void {}

  //implement these methods
  handleNotification(remoteMessage: object): void {}
}

MTS

MTS Default Config

export class MTSDefaults {
  locationFrequency: number = 10000; // in milli seconds (no. of seconds after which location updates will happen)
  distanceAccuracyLimit: number = 250; // in metres
  speedLimit: number = 28; // in m/s
  mode: MTSMode = MTSMode.HYBRID;
  environment: MTSEnv = MTSEnv.DEV;
  batchSize: number = 25;
  isMqttCleanSession: boolean = true;
  mqttKeepAliveInterval: number = 15 * 60; //in seconds
  maxLocationAge: number = 15000; // in milliseconds
  maxTraceSession: number = 24 * 3600 * 100; //in milliseconds
  isOdometerEnabled: boolean = true;
  retriesBeforeFallback: number = 1;
  httpFailureLimit: number = 5;
  dataSendDelay: number = 30000; // in milli seconds
  alarmTime: number = 60000; // in milli seconds
  missingSeqCheckDuration: number = 5 * 60 * 1000; // in milli seconds
  odometerPushFrequency: number = 5 * 60 * 1000; // in milli seconds
  qosLevel: number = 1; // values can be 0 ,1
}

Check For Mandatory MTS Permissions

let granted = await MtsLib.requestPermissionsForMTS();
// if granted = true : all permissions granted
// granted = false : one or more permissions denied

Init MTS

import type { MTSInitRequest } from '@foxtrotplatform/platform-coreos-mts-sdk';

let mtsDefaults = new MtsLib.MTSDefaults();
mtsDefaults.speedLimit = 5000;
mtsDefaults.locationFrequency = 10000;
mtsDefaults.environment = MtsLib.MTSEnv.PRE_PROD;
mtsDefaults.isOdometerEnabled = false;

//Change MTS default values as per your use case

// ...Use this for Initiating MTS
let mtsInitReq: MTSInitRequest = {
  appName: 'app_name',
  appVersion: '1',
  mtsDeviceID: 'deviceId', // use FCM ID here
  configData: mtsDefaults,
  baseURL: 'https://delhivery.aws.preprod.fxtrt.io/app/dispatch/v1/api/mts/',
  accessToken: 'token',
  tenantID: tenantId,
};
await MtsLib.initMTS(mtsInitReq);
//See Error Codes for Possible error types

Start MTS

let startReq: MTSStartRequest = {
  accessToken: 'token', // update access token
  resetSequence: false,
  dispatchID: '12345', // pass dispatch ID here
  expiryTime: Date.now() + 24 * 2600 * 1000, // expiry time after which MTS will stop automatically
};
await MtsLib.startMTS(startReq);

Publish Event

await MtsLib.publishEvent('TESTEVENT', { battery: 56, network: 100 });

Stop MTS

// To stop mts
await MtsLib.stopMTS();

Error Codes

PERMISSIONS_ERROR[2500] = 'Mandatory Android Permissions not provided';
MTS_INIT_ERROR[2501] = 'MTS INIT Not called! MTS Device ID is Empty';
PARAM_MISSING[2502] = 'Mandatory Paramater is missing in request';

Sync Manager

import { AppSyncManager, SdkSyncType } from '@os1-platform/dispatch-mobile';

// Start Events sync
await AppSyncManager.getInstance().startSyncing(
  false, // pass true for force sync
  SdkSyncType.EVENTS_SYNC
);

//Start Documents sync
await AppSyncManager.getInstance().startSyncing(
  false, // pass true for force sync
  SdkSyncType.DOCUMENT_SYNC
);

//Get All Events By Dispatch ID
await AppSyncManager.getInstance().getAllEvents('dsp_id');

//Get all documents By Dispatch ID
await AppSyncManager.getInstance().getAllDocuments('dsp_id');

Start Sync Manager as a Foreground Service in android

import { NativeSyncManager } from '@os1-platform/dispatch-mobile';

NativeSyncManager.startSyncManager(
  interval,
  notificationTitle,
  notificationText
);
// interval will be in seconds
NativeSyncManager.startSyncManager(
  2000,
  'Dispatch Service',
  'Syncing events...'
);

//To stop the foreground android service
NativeSyncManager.stopSyncManager();

SDK Utility methods

Download Firebase Config

import { SdkUtils } from '@os1-platform/dispatch-mobile';

await SdkUtils.getRemoteConfig(3000);
// 3000 is the number of seconds to cache the config

Download APK from Public URL

/**
 * Function to download apk file from a public URL
 * @param apkURL - URL where apk is hosted
 * @param version - expected version of apk (used for naming the file)
 * @param callback - callback for getting progress of download
 */
await SdkUtils.downloadAPK('https://apk_url.com', '1', (progress) =>
  console.log(progress.totalBytesWritten)
);

Open & Install an APK File

/**
 * Opens & Install an APK file
 * @param uri - source of apk file
 */

await SdkUtils.openAPKFile(result.uri);

Send events to Firebase analytics

/**
 *
 * @param eventName-> string
 * @param tag -> string
 * @param message -> string
 */
await Logger.getInstance().sendToFirebaseAnalytics('ev_name', 'tag', 'message');

Log events to console

/**
 *
 * @param TAG
 * @param message
 * @param logType
 */
Logger.getInstance().logEvent('tag', 'message', LOG_TYPE.SDK_ERROR);

Error Codes

const enum BaseErrorCodes {
  InvalidArgumentError = '100100',
  InvalidBaseURL = '100101',
  SyncManagerNotInitialized = '100102',
  MissingOrInvalidProps = '100103',
  SQLiteDBIssue = '100104',
  AppSyncNotInitialized = '100105',
  FMS_FOLDER_CREATION_ERROR = '100106',
  REASON_CODE_API_ERROR = '100107',
  MERGING_ERROR = '100108',
  LOCATION_PERMISSION_DENIED = '100109',
  CAMERA_PERMISSION_DENIED = '100110',
  STORAGE_PERMISSION_DENIED = '100111',
  GRAPHQL_CLIENT_NOT_INITIALIZED = '100112',
  FMS_GRAPHQL_API_ERROR = '100113',
  INTERNET_NOT_ENABLED = '100114',
  LOCATION_OR_GPS_NOT_ENABLED = '100115',
  EXECUTION_ENGINE_ERROR = '100116',
  UNEXPECTED_ERROR = '100117',
}

Package Sidebar

Install

npm i @os1-platform/dispatch-mobile

Weekly Downloads

4

Version

2.1.9

License

MIT

Unpacked Size

5.44 MB

Total Files

1101

Last publish

Collaborators

  • kshitijsharmadelhivery
  • bhatupanshu
  • u-anand
  • garima-delhivery
  • pavanbhat