Create and open deep links universally across React Native, Expo, and web platforms
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Advanced scheme resolution and validation for Expo and React Native applications, handling development vs production environments and app configuration.
Determines if the app uses a custom URL scheme based on the execution environment.
/**
* Check if app uses custom URL scheme based on execution environment
* - Bare workflow: always uses custom scheme
* - Standalone: uses custom scheme when defined in manifest
* - Store client (Expo Go): uses default scheme
* @returns true if app uses custom scheme, false otherwise
*/
function hasCustomScheme(): boolean;Usage Example:
import { hasCustomScheme } from "expo-linking";
if (hasCustomScheme()) {
console.log("App uses custom scheme - deep links will use app-specific protocol");
} else {
console.log("App uses default scheme - likely running in Expo Go");
}Retrieves platform-specific schemes from the Expo configuration manifest.
/**
* Collect a list of platform schemes from the manifest.
* Based on the Scheme modules from @expo/config-plugins used for collecting schemes before prebuilding.
* Resolution order:
* - Android: scheme -> android.scheme -> android.package
* - iOS: scheme -> ios.scheme -> ios.bundleIdentifier
* @returns Array of scheme strings defined in the app configuration
*/
function collectManifestSchemes(): string[];Usage Example:
import { collectManifestSchemes } from "expo-linking";
const schemes = collectManifestSchemes();
console.log("Available schemes:", schemes);
// Example output: ["myapp", "myapp-dev", "com.company.myapp"]
// Check if specific scheme is available
const hasDevScheme = schemes.includes("myapp-dev");
if (hasDevScheme) {
console.log("Development scheme is configured");
}Verifies that the expo-constants manifest is properly linked in bare workflow.
/**
* Ensure the user has linked the expo-constants manifest in bare workflow.
* Required for scheme resolution and deep linking functionality.
* @returns true if constants manifest is available, false otherwise
*/
function hasConstantsManifest(): boolean;Usage Example:
import { hasConstantsManifest } from "expo-linking";
if (!hasConstantsManifest()) {
console.warn("expo-constants manifest not found - deep linking may not work properly");
console.warn("Follow setup instructions: https://github.com/expo/expo/blob/main/packages/expo-constants/README.md");
}Resolves the appropriate scheme for deep linking with validation and environment handling.
/**
* Resolve appropriate scheme for deep linking, handles validation and warnings.
* Throws errors in production if no scheme is configured.
* @param options - Configuration options for scheme resolution
* @returns The resolved scheme string
* @throws Error if no scheme is configured in production builds
*/
function resolveScheme(options: ResolveSchemeOptions): string;
interface ResolveSchemeOptions {
/** Preferred scheme to use - will be validated against app config */
scheme?: string;
/** Whether to suppress validation warnings in development */
isSilent?: boolean;
}Usage Examples:
import { resolveScheme } from "expo-linking";
// Use default scheme from app config
const defaultScheme = resolveScheme({});
console.log("Default scheme:", defaultScheme);
// Use specific scheme with validation
const customScheme = resolveScheme({
scheme: "myapp-production"
});
console.log("Custom scheme:", customScheme);
// Silent resolution (no warnings)
const silentScheme = resolveScheme({
scheme: "myapp-dev",
isSilent: true
});Environment-Specific Behavior:
'exp' or provided scheme if it's a valid Expo client schemeimport {
resolveScheme,
collectManifestSchemes,
hasCustomScheme
} from "expo-linking";
function getOptimalScheme(environment: 'dev' | 'staging' | 'prod'): string {
const availableSchemes = collectManifestSchemes();
// Select scheme based on environment
const envSchemeMap = {
dev: `myapp-dev`,
staging: `myapp-staging`,
prod: `myapp`
};
const preferredScheme = envSchemeMap[environment];
if (availableSchemes.includes(preferredScheme)) {
return resolveScheme({ scheme: preferredScheme });
}
// Fallback to default
return resolveScheme({});
}import {
collectManifestSchemes,
hasCustomScheme,
hasConstantsManifest
} from "expo-linking";
interface SchemeValidationResult {
isValid: boolean;
hasCustomScheme: boolean;
availableSchemes: string[];
warnings: string[];
errors: string[];
}
function validateSchemeSetup(): SchemeValidationResult {
const warnings: string[] = [];
const errors: string[] = [];
// Check if constants manifest is available
if (!hasConstantsManifest()) {
errors.push("expo-constants manifest not found");
}
const schemes = collectManifestSchemes();
const customScheme = hasCustomScheme();
if (!customScheme && schemes.length === 0) {
warnings.push("No custom scheme configured - app may not handle deep links properly in production");
}
if (schemes.length > 1) {
warnings.push(`Multiple schemes found: ${schemes.join(', ')} - first scheme will be used by default`);
}
return {
isValid: errors.length === 0,
hasCustomScheme: customScheme,
availableSchemes: schemes,
warnings,
errors
};
}
// Usage
const validation = validateSchemeSetup();
if (!validation.isValid) {
console.error("Scheme setup errors:", validation.errors);
}
if (validation.warnings.length > 0) {
console.warn("Scheme setup warnings:", validation.warnings);
}{
"expo": {
"scheme": "myapp",
"ios": {
"bundleIdentifier": "com.company.myapp",
"scheme": "myapp-ios"
},
"android": {
"package": "com.company.myapp",
"scheme": "myapp-android"
}
}
}{
"expo": {
"scheme": ["myapp", "myapp-dev", "myapp-staging"]
}
}