# Migration Guide

# Migration guide
## Migration to 4.1.0
### Upload error screen customization on Android:

If you previously customized the upload error screen, add the following new string resource:

*Add this string:*
```<string name="onboard_sdk_validation_error_button_text">Scan your ID</string>```

*Previous string:*
```<string name="onboard_sdk_id_capture_tutorial_title">Scan your ID</string>```

This string is now used only for customizing the ID Capture V2 tutorial screen title.

### Changed default values in FaceMatch module config on Android (optional)

With the move to UxV2, the showUserExists config is now false by default.

### Migrate any custom ThemeConfiguration to the V2 equivalent on Android

If your previous integration had any UI customization in supported modules through Theme Configuration, these customizations will now need to be migrated to the equivalents in UXv2. See the [Migrating Theme Configurations to UXv2 Guide](https://developer.incode.com/docs/user-guide-customization#7-v2-customization-guide) for more details.

## Migration to 4.0.0

### Update string resources for the "Need Help" screen in the `IdScan` v2 module on Android

The "Need Help" screen has been redesigned on Android, and the customizable strings have been replaced.
If you override any of the following strings in your app, replace them with the new ones listed below.

No action is required if you do not override these strings.

#### Replaced string resources

Replace overrides of:

```xml
<string name="onboard_sdk_id_capture_help_title">Need help?</string>
<string name="onboard_sdk_id_capture_help_subtitle">Some considerations</string>
<string name="onboard_sdk_id_capture_help_manual_photo_button_text">Take the photo manually</string>
<string name="onboard_sdk_id_capture_help_align_title">Center your document in the frame</string>
<string name="onboard_sdk_id_capture_help_align_subtitle">The photo will be taken automatically</string>
<string name="onboard_sdk_id_capture_help_blur_title">Avoid blurriness on the document</string>
<string name="onboard_sdk_id_capture_help_blur_subtitle">Zoom in and out, or tap on the document</string>
<string name="onboard_sdk_id_capture_help_glare_title">Avoid glare on the document</string>
<string name="onboard_sdk_id_capture_help_glare_subtitle">Find a better lighting to avoid reflections</string>
<string name="onboard_sdk_id_capture_help_darkness_title">Avoid darkness on the document</string>
<string name="onboard_sdk_id_capture_help_darkness_subtitle">Find a place with better lighting</string>
```

with:

```xml
<string name="onboard_sdk_id_capture_common_issues_title">Common issues</string>
<string name="onboard_sdk_id_capture_common_issues_glare_title">Glare present</string>
<string name="onboard_sdk_id_capture_common_issues_glare_subtitle">Tilt the ID slightly up or down to minimize the reflection</string>
<string name="onboard_sdk_id_capture_common_issues_blur_title">Blur present</string>
<string name="onboard_sdk_id_capture_common_issues_blur_subtitle">Move ID further away or closer to your phone until the image is focused</string>
<string name="onboard_sdk_id_capture_common_issues_info_not_readable_title">Info is not readable</string>
<string name="onboard_sdk_id_capture_common_issues_info_not_readable_subtitle">Minimize camera shake by holding your phone steady</string>
<string name="onboard_sdk_id_capture_common_issues_try_again_button">@string/onboard_sdk_try_again</string>
```

### Upgrade compileSdk on Android

With the update of the internal CameraX dependencies, you will need to upgrade your project's `compileSdk` to level 35:

```groovy
compileSdk 35
```

### Update Gradle Wrapper on Android

Android Gradle Wrapper `8.6.0` requires Gradle `8.7` or higher.
Update your Gradle wrapper configuration in `gradle/wrapper/gradle-wrapper.properties`:

```properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
```

### If you use any of the following optional dependencies on Android, make sure to update to the latest versions

```groovy
implementation 'com.incode.sdk:nfc:1.5.2'
```

### Response Key Name Changes (Breaking Changes)

This version introduces **breaking changes** to ensure cross-platform consistency between Android and iOS response structures. The following response keys have been renamed:

#### Phone Number Module
**Before:**
```javascript
{
  "phone": {
    "phone": "+1234567890"
  }
}
```

**After:**
```javascript
{
  "phoneData": {
    "phone": "+1234567890"
  }
}
```

**Migration:** Update your code to use `phoneData` instead of `phone` when accessing phone number results.

```diff
  cordova.exec(function(winParam) {
-   const phoneNumber = winParam.phone.phone;
+   const phoneNumber = winParam.phoneData.phone;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addPhone"}]);
```

#### Signature Module
**Before:**
```javascript
{
  "signaturePath": {
    "status": "success"
  }
}
```

**After:**
```javascript
{
  "signatureData": {
    "status": "success"
  }
}
```

**Migration:** Update your code to use `signatureData` instead of `signaturePath` when accessing signature results.

```diff
  cordova.exec(function(winParam) {
-   const status = winParam.signaturePath.status;
+   const status = winParam.signatureData.status;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addSignature"}]);
```

#### Face Match Module - Existing User Field
**Before:**
```javascript
{
  "faceMatchData": {
    "status": "match",
    "confidence": 1,
    "isExistingUser": true,
    "isFaceMatched": true,
    "isNameMatched": true
  }
}
```

**After:**
```javascript
{
  "faceMatchData": {
    "status": "match",
    "confidence": 1,
    "existingUser": true,
    "isFaceMatched": true,
    "isNameMatched": true
  }
}
```

**Migration:** Update your code to use `existingUser` instead of `isExistingUser` when accessing face match results.

```diff
  cordova.exec(function(winParam) {
-   const isExisting = winParam.faceMatchData.isExistingUser;
+   const isExisting = winParam.faceMatchData.existingUser;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addFaceMatch"}]);
```

#### Geolocation Module
**Before:**
```javascript
{
  "geodata": {
    "addressFields": {
      "city": "Belgrade",
      "colony": "Zvezdara",
      "postalCode": "",
      "street": "Banjska",
      "state": ""
    }
  }
}
```

**After:**
```javascript
{
  "geoLocationData": {
    "addressFields": {
      "city": "Belgrade",
      "colony": "Zvezdara",
      "postalCode": "",
      "street": "Banjska",
      "state": ""
    }
  }
}
```

**Migration:** Update your code to use `geoLocationData` instead of `geodata` when accessing geolocation results.

```diff
  cordova.exec(function(winParam) {
-   const city = winParam.geodata.addressFields.city;
+   const city = winParam.geoLocationData.addressFields.city;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addGeolocation"}]);
```

#### User Consent Module (New Standardized Key)
**Before:**
```javascript
// User consent result was previously returned inconsistently or not at all
```

**After:**
```javascript
{
  "userConsentData": {
    "status": true
  }
}
```

**Migration:** If you're using the user consent module, the result is now consistently returned under the `userConsentData` key on both platforms.

```javascript
  cordova.exec(function(winParam) {
    const consentGiven = winParam.userConsentData.status;
    // Process consent status
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [
    {"module":"addUserConsent", "title":"Privacy Policy", "content":"..."}
  ]);
```

### Why These Changes?

These changes ensure that the JavaScript layer receives identical response structures from both Android and iOS platforms, making it easier to write cross-platform code without platform-specific conditionals.

#### Document Validation Module - `documentData` Structure

**After (Version 4.0.0):**
```javascript
{
  "documentData": {
    "type": "addressStatement",     
    "image": "<base64String>",      
    "address": {                    
      "city": "",
      "colony": "",
      "postalCode": "",
      "street": "",
      "state": ""
    },
    "data": "<rawData>"            
  }
}
```

**Migration:** The structure is now standardized with clear field names. The `type` field indicates the document type (e.g., "addressStatement", "medicalDoc", "paymentProof"), `image` contains the base64-encoded image, and `address` contains structured address information when available.

#### ID Scan Module - `frontIdData` and `backIdData` Structure

**Before:**
```javascript
{
  "frontIdData": {
    "scanStatus": "success",
    "idImageBase64": "<base64String>",
    // ... other Gson-serialized fields
  }
}
```

**After (Version 4.0.0):**
```javascript
{
  "frontIdData": {
    "status": "ok",                   // Renamed from 'scanStatus'. On success: "ok", on error: "unknown", "errorClassification", "errorGlare", "errorSharpness", "errorReadability", "errorInCapture" (iOS only), "errorUnacceptableID" (iOS only), "wrongSide" (iOS only)
    "image": "<base64String>",        // Renamed from 'idImageBase64'
    "classifiedIdType": "ID",         // Classified document type
    "idCategory": "primary",          // 'primary' or 'secondary'
    "chosenIdType": "id"             // Chosen ID type: 'id' or 'passport'
  }
}
```

**Migration:** Update your code to use the new field names:

```diff
  cordova.exec(function(winParam) {
-   const scanStatus = winParam.frontIdData.scanStatus;
+   const scanStatus = winParam.frontIdData.status;
-   const idImage = winParam.frontIdData.idImageBase64;
+   const idImage = winParam.frontIdData.image;
+   const idCategory = winParam.frontIdData.idCategory;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"addFrontId"}]);
```

**Note:** The same structure applies to `backIdData`.

#### ID Process Module - `processIdData` Structure

**After (Version 4.0.0):**
```javascript
{
  "processIdData": {
    "extendedOcrData": "<jsonString>",  // Extended OCR data as JSON string
    "data": {                            // Structured OCR data
      "address": {                       // Address fields
        "city": "",
        "colony": "",
        "postalCode": "",
        "street": "",
        "state": ""
      },
      "fullAddress": "",                 // Complete address string
      "birthDate": 0,                    // Timestamp in milliseconds
      "expirationDate": 0,               // Unix timestamp
      "gender": "",
      "name": "",                        // Full name
      "issueDate": 0,                    // Unix timestamp
      "numeroEmisionCredencial": ""      // Credential emission number
    }
  }
}
```

**Migration:** The OCR data is now structured with clear field names and types. Date fields are provided as timestamps for easier manipulation. Access the structured data through the `data` field:

```javascript
cordova.exec(function(winParam) {
  const ocrData = winParam.processIdData.data;
  const fullName = ocrData.name;
  const birthDate = new Date(ocrData.birthDate);
  const address = ocrData.address.city;
}, function(err) {
  console.log("Error: "+ err);
}, "Cplugin", "startOnboardingSection", [{"module":"processId"}]);
```

#### Selfie Scan Module - `selfieData` Structure

**After (Version 4.0.0):**
```javascript
{
  "selfieData": {
    "status": "success",           
    "image": "<base64String>",     
    "spoofAttempt": false         
  }
}
```

**Migration:** The structure now includes explicit status and spoof detection fields for better fraud prevention handling.

#### Government Validation Module - `govresult` Structure

**Before:**
```javascript
{
  "govresult": true  
}
```

**After (Version 4.0.0):**
```javascript
{
  "govresult": {
    "status": true  
  }
}
```

**Migration:** Update your code to access the status field within the govresult object:

```diff
  cordova.exec(function(winParam) {
-   const isValidated = winParam.govresult;
+   const isValidated = winParam.govresult.status;
  }, function(err) {
    console.log("Error: "+ err);
  }, "Cplugin", "startOnboardingSection", [{"module":"governmentValidation"}]);
```

#### Approve Module - `approveData` Structure

**After (Version 4.0.0):**
```javascript
{
  "approveData": {
    "status": "approved",           
    "id": "<uuid>",                 
    "customerToken": "<token>"     
  }
}
```

**Migration:** The approve result is now structured with clear field names. Previously all fields from the ApproveResult object were serialized via Gson. Now only the essential fields are exposed with consistent naming.

```javascript
cordova.exec(function(winParam) {
  const approvalStatus = winParam.approveData.status;
  const sessionId = winParam.approveData.id;
  const token = winParam.approveData.customerToken;
}, function(err) {
  console.log("Error: "+ err);
}, "Cplugin", "startOnboardingSection", [{"module":"approve"}]);
```

#### NFC Scan Module - `nfcData` Structure

**After (Version 4.0.0):**
```javascript
{
  "nfcData": {
    "birthDate": "",                        
    "compositeCheckDigit": "",              
    "dateOfBirthCheckDigit": "",            
    "documentCode": "",                     
    "documentNumber": "",                  
    "documentNumberCheckDigit": "",          
    "expirationDateCheckDigit": "",         
    "expireAt": "",                         
    "gender": "",                           
    "issuingStateOrOrganization": "",       
    "nationality": "",                      
    "optionalData1": "",                    
    "optionalData2": "",                    
    "personalNumber": "",                   
    "personalNumberCheckDigit": "",         
    "primaryIdentifier": "",                
    "secondaryIdentifier": "",              
    "status": true                          
  }
}
```

**Migration:** The NFC data structure provides comprehensive passport/ID chip information read from NFC-enabled documents. All fields are extracted from the MRZ (Machine Readable Zone) and chip data.

## Migration to 3.0.0
- It is mandatory that all sample apps now have to provide a source from where to fetch Incode's Android dependency from. For suggested method please check out the README.md [page](https://developer.incode.com/docs/cordova-sdk) and its Additional Steps for Android section.

## Migration to 2.9.0

### Optional dependencies
For Android, if you use any of the following optional dependencies, make sure to update to the latest versions

```groovy
implementation 'com.incode.sdk:video-streaming:1.6.0'
implementation 'com.incode.sdk:extensions:1.2.1'
implementation 'com.incode.sdk:model-face-recognition:3.5.1'
implementation 'com.incode.sdk:model-id-face-detection:3.5.1'
implementation 'com.incode.sdk:model-liveness-detection:3.2.1'
```

### Android minSdk changes
For Android, if you use the video-streaming dependency, you need to upgrade your minSdk to 24 or higher. The requirement is coming from the OpenTok dependency, which now requires a minimum SDK version of 24. This update is necessary to ensure compatibility with the 16KB page size support mandated by Google starting from November 1st 2025. More info (https://developer.android.com/guide/practices/page-sizes).


## Migration to 2.7.0

For Android, if you use any of the following optional dependencies, make sure to update to the latest versions
```groovy
implementation 'com.incode.sdk:model-face-recognition:3.5.0'
implementation 'com.incode.sdk:model-id-face-detection:3.5.0'
```
The `qr-face-login` dependency is no longer available and has been removed in this version of the SDK. Please update your project configuration accordingly.
Remove the `qr-face-login` dependency from your `build.gradle`:

- Update Android `minSdkVersion` in you Android projects's `build.gradle`:

```diff
  buildscript {
    ext {
-    minSdkVersion = 21
+    minSdkVersion = 23
    }
  }

```

Remove `com.incode.sdk:camera:1.1.0` dependency in your app’s `build.gradle` file:

```diff
  dependencies {
-    implementation 'com.incode.sdk:camera:1.1.0'
  }
```

## Migration to 2.5.0

- Update Android to `compileSdk=34`. It can be done by updating `cordova-android` package in `package.json`:

```diff
+ "cordova-android": "^13.0.0",
```

- Update iOS deployment target to minimum version `13.0` and swift version to `5.0`. Update `config.xml`:

```diff
+ <platform name="ios">
+    <preference name="SwiftVersion" value="5.0" />
+    <preference name="deployment-target" value="13.0" />
+ </platform>
```
