or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animation.mdcore-components.mdindex.mdnative-bridge.mdplatform-apis.mdreact-hooks.mdstyling.mduser-interaction.md

platform-apis.mddocs/

0

# React Native Platform APIs

1

2

React Native provides comprehensive platform APIs for accessing device information, system state, and platform-specific functionality across iOS and Android.

3

4

## Installation

5

6

```bash

7

npm install react-native

8

```

9

10

## Device Information APIs

11

12

### Platform

13

14

Access platform-specific information and enable conditional code execution.

15

16

```javascript { .api }

17

// ESM

18

import {Platform} from 'react-native';

19

20

// CommonJS

21

const {Platform} = require('react-native');

22

23

// Platform detection

24

console.log(Platform.OS); // 'ios' | 'android' | 'windows' | 'macos' | 'web'

25

console.log(Platform.Version); // iOS: '14.0', Android: 30

26

27

// iOS specific checks

28

if (Platform.OS === 'ios') {

29

console.log('Running on iOS');

30

console.log('Is iPad:', Platform.isPad); // boolean

31

}

32

33

// Platform-specific values

34

const styles = StyleSheet.create({

35

container: {

36

marginTop: Platform.OS === 'ios' ? 20 : 0,

37

...Platform.select({

38

ios: {

39

backgroundColor: 'red',

40

},

41

android: {

42

backgroundColor: 'blue',

43

},

44

default: {

45

backgroundColor: 'gray',

46

},

47

}),

48

},

49

});

50

51

// Platform selection utility

52

const instructions = Platform.select({

53

ios: 'Press Cmd+R to reload',

54

android: 'Double tap R on your keyboard to reload',

55

default: 'Press F5 to reload',

56

});

57

58

// Version comparisons

59

if (Platform.Version >= 21) {

60

// Android API 21+ specific code

61

}

62

```

63

64

```typescript { .api }

65

interface PlatformStatic {

66

// Platform identification

67

OS: 'ios' | 'android' | 'windows' | 'macos' | 'web';

68

Version: string | number; // iOS: string, Android: number

69

70

// iOS specific

71

isPad?: boolean;

72

isTesting?: boolean;

73

74

// Utility methods

75

select<T>(specifics: PlatformSelectSpec<T>): T;

76

}

77

78

interface PlatformSelectSpec<T> {

79

ios?: T;

80

android?: T;

81

windows?: T;

82

macos?: T;

83

web?: T;

84

native?: T;

85

default?: T;

86

}

87

```

88

89

### Dimensions

90

91

Get device screen and window dimensions with automatic updates on orientation changes.

92

93

```javascript { .api }

94

import {Dimensions} from 'react-native';

95

96

// Get current dimensions

97

const screenData = Dimensions.get('screen');

98

const windowData = Dimensions.get('window');

99

100

console.log('Screen dimensions:', screenData);

101

// {width: 414, height: 896, scale: 3, fontScale: 1}

102

103

console.log('Window dimensions:', windowData);

104

// {width: 414, height: 818, scale: 3, fontScale: 1}

105

106

// Listen for dimension changes

107

const subscription = Dimensions.addEventListener('change', ({window, screen}) => {

108

console.log('New window dimensions:', window);

109

console.log('New screen dimensions:', screen);

110

});

111

112

// Clean up listener

113

return () => subscription?.remove();

114

115

// Calculate responsive sizes

116

const {width: screenWidth, height: screenHeight} = Dimensions.get('window');

117

const isLandscape = screenWidth > screenHeight;

118

const isTablet = screenWidth >= 768;

119

120

const styles = StyleSheet.create({

121

container: {

122

width: screenWidth * 0.9,

123

height: isTablet ? screenHeight * 0.7 : screenHeight * 0.5,

124

},

125

});

126

127

// Hook for reactive dimensions

128

import {useWindowDimensions} from 'react-native';

129

130

function ResponsiveComponent() {

131

const {width, height, scale, fontScale} = useWindowDimensions();

132

133

return (

134

<View style={{

135

width: width * 0.8,

136

height: height * 0.6,

137

}}>

138

<Text>Responsive content</Text>

139

</View>

140

);

141

}

142

```

143

144

```typescript { .api }

145

interface ScaledSize {

146

width: number;

147

height: number;

148

scale: number;

149

fontScale: number;

150

}

151

152

interface DimensionsStatic {

153

// Get dimensions

154

get(dim: 'window' | 'screen'): ScaledSize;

155

156

// Event listening

157

addEventListener(

158

type: 'change',

159

handler: (dims: {window: ScaledSize; screen: ScaledSize}) => void

160

): {remove: () => void};

161

}

162

163

interface DimensionsChangeEvent {

164

window: ScaledSize;

165

screen: ScaledSize;

166

}

167

```

168

169

### PixelRatio

170

171

Access device pixel density information for high-DPI displays and responsive design.

172

173

```javascript { .api }

174

import {PixelRatio} from 'react-native';

175

176

// Get pixel ratio

177

const pixelRatio = PixelRatio.get();

178

console.log('Device pixel ratio:', pixelRatio); // 2, 3, etc.

179

180

// Get font scale

181

const fontScale = PixelRatio.getFontScale();

182

console.log('Font scale:', fontScale); // 1, 1.3, etc.

183

184

// Convert dp to pixels

185

const dpValue = 100;

186

const pixelValue = PixelRatio.getPixelSizeForLayoutSize(dpValue);

187

console.log(`${dpValue}dp = ${pixelValue}px`);

188

189

// Round to nearest pixel

190

const exactPixel = PixelRatio.roundToNearestPixel(100.4);

191

console.log('Rounded pixel:', exactPixel); // 100 or 101

192

193

// Responsive image sizing

194

const imageSize = {

195

width: PixelRatio.getPixelSizeForLayoutSize(200),

196

height: PixelRatio.getPixelSizeForLayoutSize(150),

197

};

198

199

// High DPI image selection

200

function getImageSource() {

201

const ratio = PixelRatio.get();

202

if (ratio >= 3) {

203

return require('./image@3x.png');

204

} else if (ratio >= 2) {

205

return require('./image@2x.png');

206

} else {

207

return require('./image.png');

208

}

209

}

210

211

// Pixel-perfect styling

212

const styles = StyleSheet.create({

213

hairlineWidth: {

214

borderBottomWidth: StyleSheet.hairlineWidth, // 1 / PixelRatio.get()

215

},

216

pixelPerfect: {

217

width: PixelRatio.roundToNearestPixel(100.7),

218

height: PixelRatio.roundToNearestPixel(50.3),

219

},

220

});

221

```

222

223

```typescript { .api }

224

interface PixelRatioStatic {

225

// Pixel ratio information

226

get(): number;

227

getFontScale(): number;

228

229

// Conversion utilities

230

getPixelSizeForLayoutSize(layoutSize: number): number;

231

roundToNearestPixel(layoutSize: number): number;

232

233

// Constants

234

startDetecting?(): void;

235

stopDetecting?(): void;

236

}

237

```

238

239

### DeviceInfo

240

241

Access device-specific information and constants.

242

243

```javascript { .api }

244

import {DeviceInfo} from 'react-native';

245

246

// Device information (varies by platform)

247

console.log('Device info:', DeviceInfo);

248

249

// Common usage patterns for device detection

250

const isIOS = Platform.OS === 'ios';

251

const isAndroid = Platform.OS === 'android';

252

253

// Screen size categories

254

const {width} = Dimensions.get('window');

255

const isPhone = width < 768;

256

const isTablet = width >= 768;

257

258

// Device capability detection

259

const pixelRatio = PixelRatio.get();

260

const isHighDPI = pixelRatio >= 2;

261

262

// Platform version checks

263

const isModernAndroid = Platform.OS === 'android' && Platform.Version >= 23;

264

const isModernIOS = Platform.OS === 'ios' && parseFloat(Platform.Version) >= 14;

265

```

266

267

```typescript { .api }

268

interface DeviceInfoStatic {

269

// Device constants and information

270

[key: string]: any;

271

}

272

```

273

274

## System State APIs

275

276

### AppState

277

278

Monitor application state changes (active, background, inactive) and respond to app lifecycle events.

279

280

```javascript { .api }

281

import {AppState} from 'react-native';

282

283

// Get current app state

284

const currentState = AppState.currentState;

285

console.log('Current app state:', currentState); // 'active' | 'background' | 'inactive'

286

287

// Listen for app state changes

288

const handleAppStateChange = (nextAppState) => {

289

console.log('App state changed to:', nextAppState);

290

291

if (nextAppState === 'active') {

292

// App came to foreground

293

console.log('App is now active');

294

} else if (nextAppState === 'background') {

295

// App went to background

296

console.log('App is now in background');

297

} else if (nextAppState === 'inactive') {

298

// App is transitioning between states (iOS only)

299

console.log('App is inactive');

300

}

301

};

302

303

// Add event listener

304

const subscription = AppState.addEventListener('change', handleAppStateChange);

305

306

// Remove event listener

307

subscription.remove();

308

309

// React hook for app state

310

import {useEffect, useState} from 'react';

311

312

function useAppState() {

313

const [appState, setAppState] = useState(AppState.currentState);

314

315

useEffect(() => {

316

const subscription = AppState.addEventListener('change', setAppState);

317

return () => subscription.remove();

318

}, []);

319

320

return appState;

321

}

322

323

// Usage in component

324

function AppStateComponent() {

325

const appState = useAppState();

326

327

useEffect(() => {

328

if (appState === 'active') {

329

// Refresh data when app becomes active

330

refreshData();

331

}

332

}, [appState]);

333

334

return (

335

<View>

336

<Text>App State: {appState}</Text>

337

</View>

338

);

339

}

340

341

// Pause/resume functionality

342

useEffect(() => {

343

const subscription = AppState.addEventListener('change', (nextAppState) => {

344

if (nextAppState === 'background') {

345

// Pause expensive operations

346

pauseAnimations();

347

pauseTimers();

348

} else if (nextAppState === 'active') {

349

// Resume operations

350

resumeAnimations();

351

resumeTimers();

352

}

353

});

354

355

return () => subscription.remove();

356

}, []);

357

```

358

359

```typescript { .api }

360

type AppStateStatus = 'active' | 'background' | 'inactive';

361

362

interface AppStateStatic {

363

// Current state

364

currentState: AppStateStatus;

365

366

// Event listening

367

addEventListener(

368

type: 'change',

369

listener: (state: AppStateStatus) => void

370

): {remove: () => void};

371

372

// Legacy methods (deprecated)

373

removeEventListener?(type: 'change', listener: Function): void;

374

}

375

```

376

377

### BackHandler

378

379

Handle hardware back button on Android devices.

380

381

```javascript { .api }

382

import {BackHandler} from 'react-native';

383

384

// Basic back handler (Android only)

385

useEffect(() => {

386

const backAction = () => {

387

Alert.alert('Hold on!', 'Are you sure you want to go back?', [

388

{

389

text: 'Cancel',

390

onPress: () => null,

391

style: 'cancel',

392

},

393

{text: 'YES', onPress: () => BackHandler.exitApp()},

394

]);

395

return true; // Prevent default behavior

396

};

397

398

const backHandler = BackHandler.addEventListener('hardwareBackPress', backAction);

399

400

return () => backHandler.remove();

401

}, []);

402

403

// Navigation back handling

404

import {useNavigation} from '@react-navigation/native';

405

406

function ScreenWithCustomBack() {

407

const navigation = useNavigation();

408

409

useEffect(() => {

410

const backAction = () => {

411

if (hasUnsavedChanges) {

412

Alert.alert(

413

'Unsaved Changes',

414

'You have unsaved changes. Are you sure you want to leave?',

415

[

416

{text: 'Stay', style: 'cancel'},

417

{

418

text: 'Leave',

419

style: 'destructive',

420

onPress: () => navigation.goBack(),

421

},

422

]

423

);

424

return true; // Prevent default

425

}

426

return false; // Allow default behavior

427

};

428

429

const backHandler = BackHandler.addEventListener('hardwareBackPress', backAction);

430

return () => backHandler.remove();

431

}, [navigation, hasUnsavedChanges]);

432

433

return <YourScreenContent />;

434

}

435

436

// Exit app confirmation

437

function useExitAppConfirmation() {

438

useEffect(() => {

439

const backAction = () => {

440

Alert.alert('Exit App', 'Do you want to exit?', [

441

{text: 'No', style: 'cancel'},

442

{text: 'Yes', onPress: () => BackHandler.exitApp()},

443

]);

444

return true;

445

};

446

447

const backHandler = BackHandler.addEventListener('hardwareBackPress', backAction);

448

return () => backHandler.remove();

449

}, []);

450

}

451

452

// Modal back handling

453

function ModalComponent({visible, onClose}) {

454

useEffect(() => {

455

if (!visible) return;

456

457

const backAction = () => {

458

onClose();

459

return true; // Handled

460

};

461

462

const backHandler = BackHandler.addEventListener('hardwareBackPress', backAction);

463

return () => backHandler.remove();

464

}, [visible, onClose]);

465

466

return (

467

<Modal visible={visible}>

468

{/* Modal content */}

469

</Modal>

470

);

471

}

472

```

473

474

```typescript { .api }

475

interface BackHandlerStatic {

476

// Event handling

477

addEventListener(

478

eventName: 'hardwareBackPress',

479

handler: () => boolean

480

): {remove: () => void};

481

482

// App control

483

exitApp(): void;

484

485

// Legacy methods (deprecated)

486

removeEventListener?(eventName: 'hardwareBackPress', handler: Function): void;

487

}

488

```

489

490

### Keyboard

491

492

Monitor and control keyboard visibility and behavior.

493

494

```javascript { .api }

495

import {Keyboard} from 'react-native';

496

497

// Listen for keyboard events

498

useEffect(() => {

499

const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', (event) => {

500

console.log('Keyboard shown:', event.endCoordinates);

501

// {screenX, screenY, width, height, duration, easing}

502

});

503

504

const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', (event) => {

505

console.log('Keyboard hidden:', event.endCoordinates);

506

});

507

508

const keyboardWillShowListener = Keyboard.addListener('keyboardWillShow', (event) => {

509

console.log('Keyboard will show:', event.endCoordinates);

510

});

511

512

const keyboardWillHideListener = Keyboard.addListener('keyboardWillHide', (event) => {

513

console.log('Keyboard will hide:', event.endCoordinates);

514

});

515

516

return () => {

517

keyboardDidShowListener.remove();

518

keyboardDidHideListener.remove();

519

keyboardWillShowListener.remove();

520

keyboardWillHideListener.remove();

521

};

522

}, []);

523

524

// Dismiss keyboard

525

const dismissKeyboard = () => {

526

Keyboard.dismiss();

527

};

528

529

<TouchableWithoutFeedback onPress={dismissKeyboard}>

530

<View style={styles.container}>

531

<TextInput placeholder="Tap outside to dismiss keyboard" />

532

</View>

533

</TouchableWithoutFeedback>

534

535

// Keyboard height tracking

536

function useKeyboardHeight() {

537

const [keyboardHeight, setKeyboardHeight] = useState(0);

538

539

useEffect(() => {

540

const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', (event) => {

541

setKeyboardHeight(event.endCoordinates.height);

542

});

543

544

const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {

545

setKeyboardHeight(0);

546

});

547

548

return () => {

549

keyboardDidShowListener.remove();

550

keyboardDidHideListener.remove();

551

};

552

}, []);

553

554

return keyboardHeight;

555

}

556

557

// Adjust view for keyboard

558

function KeyboardAwareComponent() {

559

const [bottomPadding, setBottomPadding] = useState(0);

560

561

useEffect(() => {

562

const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', (event) => {

563

setBottomPadding(event.endCoordinates.height);

564

});

565

566

const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {

567

setBottomPadding(0);

568

});

569

570

return () => {

571

keyboardDidShowListener.remove();

572

keyboardDidHideListener.remove();

573

};

574

}, []);

575

576

return (

577

<View style={[styles.container, {paddingBottom: bottomPadding}]}>

578

<TextInput style={styles.input} />

579

</View>

580

);

581

}

582

```

583

584

```typescript { .api }

585

interface KeyboardEvent {

586

endCoordinates: {

587

screenX: number;

588

screenY: number;

589

width: number;

590

height: number;

591

};

592

startCoordinates?: {

593

screenX: number;

594

screenY: number;

595

width: number;

596

height: number;

597

};

598

duration?: number;

599

easing?: string;

600

}

601

602

interface KeyboardStatic {

603

// Keyboard control

604

dismiss(): void;

605

606

// Event listeners

607

addListener(

608

eventName: KeyboardEventName,

609

callback: (event: KeyboardEvent) => void

610

): {remove: () => void};

611

612

// Legacy methods (deprecated)

613

removeListener?(eventName: KeyboardEventName, callback: Function): void;

614

removeAllListeners?(eventName: KeyboardEventName): void;

615

}

616

617

type KeyboardEventName =

618

| 'keyboardWillShow'

619

| 'keyboardDidShow'

620

| 'keyboardWillHide'

621

| 'keyboardDidHide'

622

| 'keyboardWillChangeFrame'

623

| 'keyboardDidChangeFrame';

624

```

625

626

## External Integration APIs

627

628

### Linking

629

630

Handle deep links, URL schemes, and external app integration.

631

632

```javascript { .api }

633

import {Linking} from 'react-native';

634

635

// Open external URLs

636

const openURL = async (url) => {

637

try {

638

const supported = await Linking.canOpenURL(url);

639

if (supported) {

640

await Linking.openURL(url);

641

} else {

642

Alert.alert('Error', `Don't know how to open URL: ${url}`);

643

}

644

} catch (error) {

645

Alert.alert('Error', 'An error occurred');

646

}

647

};

648

649

// Open various URL schemes

650

openURL('https://www.example.com'); // Web browser

651

openURL('mailto:support@example.com'); // Email client

652

openURL('tel:+1234567890'); // Phone dialer

653

openURL('sms:+1234567890'); // SMS

654

openURL('maps:0,0?q=restaurant'); // Maps app

655

openURL('fb://profile/123456789'); // Facebook app

656

657

// Get initial URL (app launched via deep link)

658

useEffect(() => {

659

const getInitialURL = async () => {

660

try {

661

const initialUrl = await Linking.getInitialURL();

662

if (initialUrl) {

663

console.log('App opened with URL:', initialUrl);

664

handleDeepLink(initialUrl);

665

}

666

} catch (error) {

667

console.error('Error getting initial URL:', error);

668

}

669

};

670

671

getInitialURL();

672

}, []);

673

674

// Listen for incoming URLs (app already running)

675

useEffect(() => {

676

const handleUrlChange = (event) => {

677

console.log('Received URL:', event.url);

678

handleDeepLink(event.url);

679

};

680

681

const subscription = Linking.addEventListener('url', handleUrlChange);

682

return () => subscription.remove();

683

}, []);

684

685

// Deep link handler

686

const handleDeepLink = (url) => {

687

const route = url.replace(/.*?:\/\//g, '');

688

const [routeName, paramsString] = route.split('?');

689

690

// Parse parameters

691

const params = {};

692

if (paramsString) {

693

paramsString.split('&').forEach(param => {

694

const [key, value] = param.split('=');

695

params[key] = decodeURIComponent(value);

696

});

697

}

698

699

// Navigate based on deep link

700

switch (routeName) {

701

case 'profile':

702

navigation.navigate('Profile', params);

703

break;

704

case 'product':

705

navigation.navigate('Product', {id: params.id});

706

break;

707

default:

708

navigation.navigate('Home');

709

}

710

};

711

712

// Custom URL scheme examples

713

// myapp://profile/123

714

// myapp://product?id=456&color=red

715

716

// Universal links (iOS) and App links (Android)

717

// https://myapp.com/profile/123

718

// https://myapp.com/product?id=456

719

720

// Check if URL can be opened

721

const checkURL = async (url) => {

722

try {

723

const canOpen = await Linking.canOpenURL(url);

724

console.log(`Can open ${url}:`, canOpen);

725

} catch (error) {

726

console.error('Error checking URL:', error);

727

}

728

};

729

730

// Open settings

731

const openSettings = () => {

732

Linking.openSettings();

733

};

734

```

735

736

```typescript { .api }

737

interface LinkingStatic {

738

// URL handling

739

canOpenURL(url: string): Promise<boolean>;

740

openURL(url: string): Promise<void>;

741

openSettings(): Promise<void>;

742

743

// Deep link handling

744

getInitialURL(): Promise<string | null>;

745

addEventListener(

746

type: 'url',

747

handler: (event: {url: string}) => void

748

): {remove: () => void};

749

750

// Legacy methods (deprecated)

751

removeEventListener?(type: 'url', handler: Function): void;

752

}

753

754

interface LinkingEvent {

755

url: string;

756

}

757

```

758

759

### Share

760

761

Invoke the native share dialog to share content with other apps.

762

763

```javascript { .api }

764

import {Share} from 'react-native';

765

766

// Basic text sharing

767

const shareText = async () => {

768

try {

769

const result = await Share.share({

770

message: 'Check out this amazing app!',

771

});

772

773

if (result.action === Share.sharedAction) {

774

if (result.activityType) {

775

console.log('Shared with activity type:', result.activityType);

776

} else {

777

console.log('Shared');

778

}

779

} else if (result.action === Share.dismissedAction) {

780

console.log('Share dismissed');

781

}

782

} catch (error) {

783

Alert.alert('Error', error.message);

784

}

785

};

786

787

// Share with title (Android)

788

const shareWithTitle = async () => {

789

try {

790

await Share.share({

791

message: 'Amazing content to share',

792

title: 'Share Title', // Android only

793

});

794

} catch (error) {

795

console.error(error);

796

}

797

};

798

799

// Share URL

800

const shareURL = async () => {

801

try {

802

await Share.share({

803

message: 'Check out this website',

804

url: 'https://www.example.com', // iOS only

805

});

806

} catch (error) {

807

console.error(error);

808

}

809

};

810

811

// Share with options (iOS)

812

const shareWithOptions = async () => {

813

try {

814

await Share.share(

815

{

816

message: 'Content to share',

817

url: 'https://example.com',

818

},

819

{

820

// iOS only

821

excludedActivityTypes: [

822

'com.apple.UIKit.activity.PostToWeibo',

823

'com.apple.UIKit.activity.Print',

824

],

825

dialogTitle: 'Share this content', // Android only

826

subject: 'Email Subject', // Email subject

827

tintColor: '#007AFF', // iOS only

828

}

829

);

830

} catch (error) {

831

console.error(error);

832

}

833

};

834

835

// Share different content types

836

const shareImage = async (imageUri) => {

837

try {

838

await Share.share({

839

message: 'Check out this image!',

840

url: imageUri, // Local file:// or remote https:// URL

841

});

842

} catch (error) {

843

console.error(error);

844

}

845

};

846

847

// Share with dynamic content

848

const shareProduct = async (product) => {

849

try {

850

const shareContent = {

851

message: `Check out ${product.name}: ${product.description}`,

852

url: `https://myapp.com/product/${product.id}`,

853

};

854

855

const shareOptions = {

856

dialogTitle: 'Share Product',

857

subject: `${product.name} - Product Recommendation`,

858

};

859

860

await Share.share(shareContent, shareOptions);

861

} catch (error) {

862

console.error('Share failed:', error);

863

}

864

};

865

866

// Component with share functionality

867

function ShareButton({content, title}) {

868

const handleShare = async () => {

869

try {

870

await Share.share({

871

message: content,

872

title,

873

});

874

} catch (error) {

875

Alert.alert('Share Failed', 'Unable to share content');

876

}

877

};

878

879

return (

880

<TouchableOpacity onPress={handleShare} style={styles.shareButton}>

881

<Text>Share</Text>

882

</TouchableOpacity>

883

);

884

}

885

```

886

887

```typescript { .api }

888

interface ShareContent {

889

message?: string;

890

title?: string; // Android only

891

url?: string; // iOS only

892

}

893

894

interface ShareOptions {

895

// iOS only

896

excludedActivityTypes?: string[];

897

tintColor?: string;

898

899

// Android only

900

dialogTitle?: string;

901

902

// Cross-platform

903

subject?: string; // For email

904

}

905

906

interface ShareResult {

907

action: 'sharedAction' | 'dismissedAction';

908

activityType?: string; // iOS only

909

}

910

911

interface ShareStatic {

912

share(content: ShareContent, options?: ShareOptions): Promise<ShareResult>;

913

914

// Action constants

915

sharedAction: 'sharedAction';

916

dismissedAction: 'dismissedAction';

917

}

918

```

919

920

## System Integration APIs

921

922

### Appearance

923

924

Detect and listen to system appearance changes (light/dark mode).

925

926

```javascript { .api }

927

import {Appearance} from 'react-native';

928

929

// Get current color scheme

930

const colorScheme = Appearance.getColorScheme();

931

console.log('Current color scheme:', colorScheme); // 'light' | 'dark' | null

932

933

// Listen for appearance changes

934

useEffect(() => {

935

const subscription = Appearance.addChangeListener(({colorScheme}) => {

936

console.log('Color scheme changed to:', colorScheme);

937

updateTheme(colorScheme);

938

});

939

940

return () => subscription.remove();

941

}, []);

942

943

// Theme context with appearance

944

const ThemeContext = createContext();

945

946

export function ThemeProvider({children}) {

947

const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());

948

949

useEffect(() => {

950

const subscription = Appearance.addChangeListener(({colorScheme}) => {

951

setColorScheme(colorScheme);

952

});

953

954

return () => subscription.remove();

955

}, []);

956

957

const theme = {

958

colors: colorScheme === 'dark' ? darkColors : lightColors,

959

colorScheme,

960

};

961

962

return (

963

<ThemeContext.Provider value={theme}>

964

{children}

965

</ThemeContext.Provider>

966

);

967

}

968

969

// Using appearance in components

970

function ThemedComponent() {

971

const colorScheme = useColorScheme(); // React Native hook

972

973

const styles = StyleSheet.create({

974

container: {

975

backgroundColor: colorScheme === 'dark' ? '#000' : '#fff',

976

color: colorScheme === 'dark' ? '#fff' : '#000',

977

},

978

});

979

980

return (

981

<View style={styles.container}>

982

<Text>Themed content</Text>

983

</View>

984

);

985

}

986

987

// Dynamic styling based on appearance

988

const createStyles = (colorScheme) => StyleSheet.create({

989

container: {

990

flex: 1,

991

backgroundColor: colorScheme === 'dark' ? '#121212' : '#ffffff',

992

},

993

text: {

994

color: colorScheme === 'dark' ? '#ffffff' : '#000000',

995

},

996

card: {

997

backgroundColor: colorScheme === 'dark' ? '#1e1e1e' : '#f5f5f5',

998

borderColor: colorScheme === 'dark' ? '#333333' : '#e0e0e0',

999

},

1000

});

1001

1002

function App() {

1003

const [colorScheme, setColorScheme] = useState(Appearance.getColorScheme());

1004

1005

useEffect(() => {

1006

const subscription = Appearance.addChangeListener(({colorScheme}) => {

1007

setColorScheme(colorScheme);

1008

});

1009

1010

return () => subscription.remove();

1011

}, []);

1012

1013

const styles = createStyles(colorScheme);

1014

1015

return (

1016

<View style={styles.container}>

1017

<Text style={styles.text}>App with dynamic theming</Text>

1018

</View>

1019

);

1020

}

1021

```

1022

1023

```typescript { .api }

1024

type ColorSchemeName = 'light' | 'dark' | null;

1025

1026

interface AppearanceStatic {

1027

// Current appearance

1028

getColorScheme(): ColorSchemeName;

1029

1030

// Event listening

1031

addChangeListener(

1032

listener: (preferences: {colorScheme: ColorSchemeName}) => void

1033

): {remove: () => void};

1034

1035

// Legacy methods (deprecated)

1036

removeChangeListener?(listener: Function): void;

1037

}

1038

1039

interface AppearancePreferences {

1040

colorScheme: ColorSchemeName;

1041

}

1042

```

1043

1044

## Network and Storage APIs

1045

1046

### I18nManager

1047

1048

Manage internationalization and right-to-left (RTL) layout support.

1049

1050

```javascript { .api }

1051

import {I18nManager} from 'react-native';

1052

1053

// Check RTL status

1054

console.log('Is RTL:', I18nManager.isRTL); // boolean

1055

1056

// Get text direction

1057

console.log('Text direction:', I18nManager.getConstants().isRTL);

1058

1059

// Force RTL (requires app restart)

1060

if (!I18nManager.isRTL) {

1061

I18nManager.forceRTL(true);

1062

// App restart required

1063

}

1064

1065

// Allow RTL layout

1066

I18nManager.allowRTL(true);

1067

1068

// RTL-aware styling

1069

const styles = StyleSheet.create({

1070

container: {

1071

flexDirection: 'row',

1072

paddingStart: 20, // Uses paddingLeft in LTR, paddingRight in RTL

1073

paddingEnd: 10, // Uses paddingRight in LTR, paddingLeft in RTL

1074

},

1075

text: {

1076

textAlign: I18nManager.isRTL ? 'right' : 'left',

1077

writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',

1078

},

1079

});

1080

1081

// RTL-aware icon direction

1082

function DirectionalIcon({name, style}) {

1083

const iconName = I18nManager.isRTL ? `${name}-left` : `${name}-right`;

1084

return <Icon name={iconName} style={style} />;

1085

}

1086

1087

// RTL-aware navigation

1088

function RTLAwareNavigation() {

1089

const slideDirection = I18nManager.isRTL ? 'right' : 'left';

1090

1091

return (

1092

<Stack.Navigator

1093

screenOptions={{

1094

gestureDirection: I18nManager.isRTL ? 'horizontal-inverted' : 'horizontal',

1095

}}

1096

>

1097

<Stack.Screen name="Home" component={HomeScreen} />

1098

</Stack.Navigator>

1099

);

1100

}

1101

```

1102

1103

```typescript { .api }

1104

interface I18nManagerStatic {

1105

// RTL state

1106

isRTL: boolean;

1107

1108

// Configuration

1109

allowRTL(allowRTL: boolean): void;

1110

forceRTL(forceRTL: boolean): void;

1111

swapLeftAndRightInRTL(flipStyles: boolean): void;

1112

1113

// Constants

1114

getConstants(): {

1115

isRTL: boolean;

1116

doLeftAndRightSwapInRTL: boolean;

1117

};

1118

}

1119

```

1120

1121

## Development and Debug APIs

1122

1123

### DevSettings

1124

1125

Access development-time settings and actions (development builds only).

1126

1127

```javascript { .api }

1128

import {DevSettings} from 'react-native';

1129

1130

// Add developer menu item (development only)

1131

if (__DEV__) {

1132

DevSettings.addMenuItem('Clear Cache', () => {

1133

// Custom cache clearing logic

1134

clearAppCache();

1135

});

1136

1137

DevSettings.addMenuItem('Reset Database', () => {

1138

Alert.alert(

1139

'Reset Database',

1140

'Are you sure?',

1141

[

1142

{text: 'Cancel', style: 'cancel'},

1143

{text: 'Reset', onPress: resetDatabase},

1144

]

1145

);

1146

});

1147

1148

DevSettings.addMenuItem('Toggle Debug Mode', () => {

1149

toggleDebugMode();

1150

});

1151

}

1152

1153

// Reload app programmatically (development only)

1154

const reloadApp = () => {

1155

if (__DEV__) {

1156

DevSettings.reload();

1157

}

1158

};

1159

1160

// Development utilities

1161

function DeveloperTools() {

1162

if (!__DEV__) return null;

1163

1164

return (

1165

<View style={styles.devTools}>

1166

<Button title="Reload" onPress={() => DevSettings.reload()} />

1167

<Button title="Clear Logs" onPress={clearLogs} />

1168

</View>

1169

);

1170

}

1171

```

1172

1173

```typescript { .api }

1174

interface DevSettingsStatic {

1175

// Developer menu

1176

addMenuItem(title: string, handler: () => void): void;

1177

1178

// App control

1179

reload(): void;

1180

}

1181

```

1182

1183

This comprehensive documentation covers all the essential platform APIs in React Native, providing developers with the tools needed to create robust, cross-platform mobile applications that integrate seamlessly with device capabilities and system features.