Skip to content
Merged
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
12 changes: 12 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## v7.6.3

### Improvements

- Improved automatic lightweight build detection for mobile devices
- Now uses Device Memory API to detect low-memory devices (< 4GB)
- Applies to all mobile devices (phones and tablets) with available memory information
- Falls back to `undefined` when memory information is unavailable, allowing manual configuration
- Previously used a simple user agent check for all mobile devices
- Updated the camera picking logic
- Improved error handling on the `Camera` class

## 7.6.2

### Bugfixes
Expand Down
17 changes: 15 additions & 2 deletions packages/blinkid-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
# @microblink/blinkid-core

## 7.6.3

### Patch Changes

- Improved automatic lightweight build detection for mobile devices
- Now uses Device Memory API to detect low-memory devices (< 4GB)
- Applies to all mobile devices (phones and tablets) with available memory information
- Falls back to `undefined` when memory information is unavailable, allowing manual configuration
- Previously used a simple user agent check for all mobile devices
- Updated dependencies
- @microblink/blinkid-worker@7.6.3
- @microblink/blinkid-wasm@7.6.3

## 7.6.2

### Patch Changes

- Fixes `microblinkProxyUrl` handling
- Prevent an extra ping to the Microblink server when a proxy URL is configured (previously one redundant request was sent).
- Preserve the user-provided path when using a proxy URL (previously the path was removed).
- Prevent an extra ping to the Microblink server when a proxy URL is configured (previously one redundant request was sent).
- Preserve the user-provided path when using a proxy URL (previously the path was removed).
- Updated dependencies
- @microblink/blinkid-wasm@7.6.2
- @microblink/blinkid-worker@7.6.2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Represents the data for the `ping.hardware.camera.info` event.

> **cameraFacing**: `"Front"` \| `"Back"` \| `"Unknown"`

#### deviceId

> **deviceId**: `string`

#### focus?

> `optional` **focus**: `"Auto"` \| `"Fixed"`
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

# Type Alias: PingHardwareCameraInfo

> **PingHardwareCameraInfo** = [`PingBase`](../interfaces/PingBase.md)\<[`HardwareCameraInfoData`](HardwareCameraInfoData.md), `"ping.hardware.camera.info"`, `"1.0.1"`, `0`\>
> **PingHardwareCameraInfo** = [`PingBase`](../interfaces/PingBase.md)\<[`HardwareCameraInfoData`](HardwareCameraInfoData.md), `"ping.hardware.camera.info"`, `"1.0.3"`, `0`\>

Represents the `ping.hardware.camera.info` event.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

# Type Alias: PingSdkCameraInputInfo

> **PingSdkCameraInputInfo** = [`PingBase`](../interfaces/PingBase.md)\<[`SdkCameraInputInfoData`](SdkCameraInputInfoData.md), `"ping.sdk.camera.input.info"`, `"1.0.1"`\>
> **PingSdkCameraInputInfo** = [`PingBase`](../interfaces/PingBase.md)\<[`SdkCameraInputInfoData`](SdkCameraInputInfoData.md), `"ping.sdk.camera.input.info"`, `"1.0.2"`\>

Represents the `ping.sdk.camera.input.info` event.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ Represents the data for the `ping.sdk.camera.input.info` event.

***

### deviceId

> **deviceId**: `string`

***

### roiHeight

> **roiHeight**: `number`
Expand Down
2 changes: 1 addition & 1 deletion packages/blinkid-core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@microblink/blinkid-core",
"description": "BlinkID Core SDK",
"version": "7.6.2",
"version": "7.6.3",
"author": "Microblink",
"scripts": {
"build": "concurrently pnpm:build:js pnpm:build:types",
Expand Down
7 changes: 2 additions & 5 deletions packages/blinkid-core/src/BlinkIdCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { createProxyWorker } from "./createProxyWorker";
import { getUserId } from "./getUserId";
import { proxy, Remote } from "comlink";
import { defaultSessionSettings } from "./defaultSessionSettings";
import { shouldUseLightweightBuild } from "./shouldUseLightweightBuild";

/**
* Configuration options for initializing the BlinkID core.
Expand Down Expand Up @@ -56,11 +57,7 @@ export async function loadBlinkIdCore(
}

if (settings.useLightweightBuild === undefined) {
// use only on desktop devices
settings.useLightweightBuild =
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent,
);
settings.useLightweightBuild = await shouldUseLightweightBuild();
}

const proxyProgressCallback = progressCallback
Expand Down
209 changes: 209 additions & 0 deletions packages/blinkid-core/src/shouldUseLightweightBuild.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**
* Copyright (c) 2025 Microblink Ltd. All rights reserved.
*/

import { describe, it, expect, vi, beforeEach } from "vitest";
import { shouldUseLightweightBuild } from "./shouldUseLightweightBuild";
import * as deviceInfoModule from "./deviceInfo/deviceInfo";
import type { DeviceInfo } from "./deviceInfo/deviceInfo";

// Mock the getDeviceInfo function
vi.mock("./deviceInfo/deviceInfo", () => ({
getDeviceInfo: vi.fn(),
}));

describe("shouldUseLightweightBuild", () => {
beforeEach(() => {
vi.clearAllMocks();
});

it("should return true for mobile device with less than 4GB memory", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 2.0,
derivedDeviceInfo: {
formFactors: ["Mobile"],
model: "Test Phone",
platform: "Android",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBe(true);
});

it("should return false for mobile device with 4GB or more memory", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 4.0,
derivedDeviceInfo: {
formFactors: ["Mobile"],
model: "Test Phone",
platform: "Android",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBe(false);
});

it("should return true for mobile device with 2GB memory", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 2,
derivedDeviceInfo: {
formFactors: ["Mobile"],
model: "Test Phone",
platform: "Android",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBe(true);
});

it("should return true for tablet device with less than 4GB memory", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 2.0,
derivedDeviceInfo: {
formFactors: ["Tablet"],
model: "Test Tablet",
platform: "Android",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBe(true);
});

it("should return undefined for mobile device without memory info", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: undefined,
derivedDeviceInfo: {
formFactors: ["Mobile"],
model: "Test Phone",
platform: "iOS",
browser: { brand: "Safari", version: "17.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBeUndefined();
});

it("should return undefined for desktop device with memory info", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 8.0,
derivedDeviceInfo: {
formFactors: ["Desktop"],
model: "Mac",
platform: "macOS",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBeUndefined();
});

it("should return undefined for desktop device without memory info", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: undefined,
derivedDeviceInfo: {
formFactors: ["Desktop"],
model: "Mac",
platform: "macOS",
browser: { brand: "Safari", version: "17.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBeUndefined();
});

it("should handle device with multiple form factors including Mobile", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 2.0,
derivedDeviceInfo: {
formFactors: ["Mobile", "Tablet"],
model: "Test Device",
platform: "Android",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBe(true);
});

it("should return true for very low memory mobile device (1GB)", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 1,
derivedDeviceInfo: {
formFactors: ["Mobile"],
model: "Budget Phone",
platform: "Android",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBe(true);
});

it("should return false for high-end mobile device (8GB)", async () => {
const mockDeviceInfo: Partial<DeviceInfo> = {
memory: 8.0,
derivedDeviceInfo: {
formFactors: ["Mobile"],
model: "Flagship Phone",
platform: "Android",
browser: { brand: "Chrome", version: "120.0" },
},
};

vi.mocked(deviceInfoModule.getDeviceInfo).mockResolvedValue(
mockDeviceInfo as DeviceInfo,
);

const result = await shouldUseLightweightBuild();
expect(result).toBe(false);
});
});
32 changes: 32 additions & 0 deletions packages/blinkid-core/src/shouldUseLightweightBuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright (c) 2025 Microblink Ltd. All rights reserved.
*/

import { getDeviceInfo } from "./deviceInfo/deviceInfo";

/**
* Determines whether to use the lightweight build based on device capabilities.
*
* This function checks if the device is mobile (Mobile or Tablet form factor) and
* has less than 4GB of memory. The lightweight build is only used for low-budget
* mobile devices where memory information is available. For iOS device this will always
* return undefined, since we don't have memory information.
*
* @returns `true` if lightweight build should be used, `false` if full build should be used,
* or `undefined` if the decision cannot be made (e.g., memory info unavailable)
*/
export async function shouldUseLightweightBuild(): Promise<
boolean | undefined
> {
const deviceInfo = await getDeviceInfo();

const isMobile = deviceInfo.derivedDeviceInfo.formFactors.some(
(formFactor) => formFactor === "Mobile" || formFactor === "Tablet",
);
if (isMobile && deviceInfo.memory !== undefined) {
return deviceInfo.memory < 4;
}

// If not mobile or memory info unavailable, return undefined
return undefined;
}
8 changes: 8 additions & 0 deletions packages/blinkid-ux-manager/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @microblink/blinkid-ux-manager

## 7.6.3

### Patch Changes

- Updated dependencies
- @microblink/camera-manager@7.2.7
- @microblink/blinkid-core@7.6.3

## 7.6.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/blinkid-ux-manager/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@microblink/blinkid-ux-manager",
"description": "BlinkID UX Manager provides user feedback based on the blinkid process results.",
"version": "7.6.2",
"version": "7.6.3",
"author": "Microblink",
"scripts": {
"build": "concurrently pnpm:build:js pnpm:build:types",
Expand Down
2 changes: 2 additions & 0 deletions packages/blinkid-ux-manager/src/core/ping-camera-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const createCameraInputInfo = ({
: videoResolution.height;

return new PingSdkCameraInputInfoImpl({
deviceId: selectedCamera.name,
cameraFacing: mapCameraFacingToPingFacing(selectedCamera.facingMode),
cameraFrameWidth: videoResolution.width,
cameraFrameHeight: videoResolution.height,
Expand All @@ -56,6 +57,7 @@ export const mapCameraFacingToPingFacing = (

export const convertCameraToPingCamera = (camera: Camera): PingCamera => {
return {
deviceId: camera.name,
cameraFacing: mapCameraFacingToPingFacing(camera.facingMode),
/** we can't know this */
availableResolutions: undefined,
Expand Down
Loading