Skip to content

feat: add device detection for (ios/android) and enable appClip default #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 26, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@reclaimprotocol/js-sdk",
"version": "3.0.1",
"version": "3.0.2",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it 3.0.3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to 3.0.3

"description": "Designed to request proofs from the Reclaim protocol and manage the flow of claims and witness interactions.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
16 changes: 16 additions & 0 deletions src/Reclaim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
import { validateContext, validateFunctionParams, validateParameters, validateSignature, validateURL } from './utils/validationUtils'
import { fetchStatusUrl, initSession, updateSession } from './utils/sessionUtils'
import { assertValidSignedClaim, createLinkWithTemplateData, getWitnessesForClaim } from './utils/proofUtils'
import { userAgentIsAndroid, userAgentIsIOS } from './utils/device'
import loggerModule from './utils/logger';
const logger = loggerModule.logger

Expand Down Expand Up @@ -174,6 +175,18 @@ export class ReclaimProofRequest {
{ paramName: 'appSecret', input: appSecret, isString: true }
], 'the constructor')

if (!options) {
options = {};
}

if (!options.device) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add this in constructor rather than init method. Set the default device and useAppClip fields in constructor

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done !

if (userAgentIsIOS) {
options.device = "ios";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add enum for 'ios'

} else if (userAgentIsAndroid) {
options.device = "android";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add enum for 'android'

}
}

// check if options is provided and validate each property of options
if (options) {
if (options.acceptAiProviders) {
Expand All @@ -186,6 +199,9 @@ export class ReclaimProofRequest {
{ paramName: 'log', input: options.log }
], 'the constructor')
}
if (options.useAppClip === undefined) {
options.useAppClip = true;
}
if (options.useAppClip) {
validateFunctionParams([
{ paramName: 'useAppClip', input: options.useAppClip }
Expand Down
19 changes: 19 additions & 0 deletions src/utils/device.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const navigatorDefined = typeof navigator !== 'undefined';
const windowDefined = typeof window !== 'undefined';

const userAgent = navigatorDefined ? navigator.userAgent.toLowerCase() : '';
const userAgentData = navigatorDefined ? (navigator as Navigator & { userAgentData?: { platform: string } }).userAgentData : undefined;

export const userAgentIsAndroid = userAgent.includes("android");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add enum for 'android'


const isIpad =
windowDefined &&
navigatorDefined &&
(userAgentData?.platform === 'iPad' || userAgent.includes('ipad'));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add enum for 'ipad'


export const userAgentIsIOS =
/iphone|ipod/i.test(userAgent) || isIpad;

export const userAgentIsMobile =
/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent) ||
(windowDefined && 'orientation' in window);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify orientation-based mobile detection reliability.

The mobile detection logic is comprehensive, but the window.orientation check may have browser compatibility issues and can be unreliable on some devices.


🌐 Web query:

Is window.orientation still a reliable way to detect mobile devices in modern browsers? Are there any deprecation warnings or better alternatives?

💡 Result:

The window.orientation property is no longer considered a reliable method for detecting mobile device orientation in modern browsers. This property has been officially deprecated and is not recommended for use in new projects or code updates.

Deprecation Status

The window.orientation property has been marked as deprecated in documentation, meaning it's no longer recommended for use[10]. Mozilla Developer Network (MDN) explicitly states: "This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes"[10]. This indicates that while the property might still function in some browsers, its long-term availability cannot be guaranteed.

Better Alternatives

Several more modern and standardized alternatives exist for detecting device orientation:

1. Screen.orientation API

The official replacement for window.orientation is the Screen.orientation property, which is available via window.screen.orientation[10]. This provides a more robust and standardized way to access orientation information.

2. matchMedia() for Orientation Detection

One of the most recommended and easiest approaches is using the window.matchMedia() method with orientation media queries:

const portrait = window.matchMedia("(orientation: portrait)").matches;
// portrait will be true or false

This method not only detects the current orientation but can also listen for orientation changes[5]:

window.matchMedia("(orientation: portrait)").addEventListener("change", e => {
  const portrait = e.matches;
  if (portrait) {
    // Handle portrait orientation
  } else {
    // Handle landscape orientation
  }
});

This approach is compatible with all major browsers, including Safari, and works reliably on mobile and tablet devices[5].

3. DeviceOrientationEvent

For more detailed orientation data, you can use the DeviceOrientationEvent, which provides precise information about device rotation along different axes:

window.addEventListener("deviceorientation", handleOrientation, true);

function handleOrientation(event) {
  const absolute = event.absolute;
  const alpha = event.alpha;    // rotation around z-axis
  const beta = event.beta;      // front to back motion (x-axis)
  const gamma = event.gamma;    // left to right motion (y-axis)
  
  // Use orientation data
}

This event provides detailed values for device rotation along different axes, including alpha (z-axis rotation), beta (x-axis rotation), and gamma (y-axis rotation)[1][3].

4. Feature Detection for Touch Capability

If your goal is specifically to detect mobile devices to optimize for touch interfaces, it's better to directly test for touch capability rather than making assumptions based on orientation:

if (navigator.maxTouchPoints > 1) {
  // Device supports multi-touch
}

This approach aligns with modern best practices of testing for specific features rather than attempting to identify device types[8].

Industry Trends

The Android platform is also moving away from allowing apps to restrict orientation. Android 16 is removing the ability for apps to restrict orientation and resizability at the platform level, shifting to a model where apps should adapt seamlessly to different screen sizes and orientations[2]. This industry-wide trend emphasizes the importance of responsive, adaptive design rather than orientation detection and restriction.

Should You Still Use window.orientation?

While window.orientation might continue to work in some contexts for backward compatibility, developers are strongly encouraged to transition to newer methods. As one forum commenter noted: "My bet is that window.orientation isn't going away soon - too much software will break. You'll see warnings in the console long before they get rid of it"[6]. However, relying on deprecated features is generally not recommended for new development.

In conclusion, for modern web development, it's best to use Screen.orientation or the matchMedia() approach for orientation detection, while focusing on responsive design principles that adapt to various screen sizes and orientations rather than trying to detect specific device types.

Citations:


Replace deprecated window.orientation check with modern APIs

The window.orientation property is deprecated and may be removed from browsers at any time. To improve reliability and future-proof our mobile detection, consider swapping it out for one or more of these approaches:

• Use the Screen Orientation API

export const userAgentIsMobile =
  /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent) ||
- (windowDefined && 'orientation' in window);
+ (windowDefined && window.screen?.orientation?.type.startsWith('portrait'));

• Or use a media query via matchMedia

- (windowDefined && 'orientation' in window);
+ (windowDefined && window.matchMedia('(orientation: portrait)').matches);

• For touch-capable devices, feature-detect touch input:

- (windowDefined && 'orientation' in window);
+ (windowDefined && navigator.maxTouchPoints > 1);

You can even combine these checks for broader coverage:

 export const userAgentIsMobile =
   /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent) ||
-  (windowDefined && 'orientation' in window);
+  (windowDefined && (
+    window.screen?.orientation?.type.startsWith('portrait') ||
+    window.matchMedia('(orientation: portrait)').matches ||
+    navigator.maxTouchPoints > 1
+  ));

This ensures robust orientation detection across modern browsers.

🤖 Prompt for AI Agents
In src/utils/device.ts around lines 17 to 19, replace the deprecated
window.orientation check with a more reliable method such as using the Screen
Orientation API (window.screen.orientation) or a media query with
window.matchMedia("(orientation: portrait)").matches. Additionally, consider
incorporating a feature detection for touch capability using
navigator.maxTouchPoints to improve mobile detection accuracy. Combine these
modern approaches to ensure robust and future-proof orientation and device type
detection across browsers.