Skip to content

Conversation

@pushpender-singh-ap
Copy link
Owner

🎯 Overview

Implements proper native camera permission callback mechanism for Android to achieve feature parity with iOS. The requestCameraPermission() method now correctly resolves based on the user's actual permission response instead of immediately returning false.

📋 Changes

Android Native Module

  • ✅ Implemented PermissionListener callback interface for handling permission results
  • ✅ Added promise storage pattern to resolve based on user action (grant/deny)
  • ✅ Switched from ActivityCompat.requestPermissions() to PermissionAwareActivity.requestPermissions()
  • ✅ Added proper cleanup in invalidate() to prevent memory leaks
  • ✅ Removed incorrect BaseActivityEventListener implementation that caused build failures

Documentation

  • ✅ Added comprehensive hasCameraPermission() API documentation
  • ✅ Added comprehensive requestCameraPermission() API documentation
  • ✅ Added ~100 line permission handling example with check → request → handle flow
  • ✅ Added Android API compatibility notes (API 23+)
  • ✅ Moved "Native permission handling" from roadmap to "Recently Completed"

Example App

  • ✅ Removed react-native-permissions dependency usage from App.tsx
  • ✅ Updated to use built-in BarcodeScanner.hasCameraPermission() and BarcodeScanner.requestCameraPermission()
  • ✅ Refactored permission checking logic with proper error handling

🔧 Technical Details

Implementation Pattern

Before (Broken):

// Promise resolved immediately with false
@ReactMethod
fun requestCameraPermission(promise: Promise) {
    ActivityCompat.requestPermissions(...)
    promise.resolve(false) // ❌ Doesn't wait for user response
}

After (Fixed):

private var permissionPromise: Promise? = null

private val permissionListener = PermissionListener { requestCode, permissions, grantResults ->
  if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
    val permissionGranted = grantResults.isNotEmpty() && 
                             grantResults[0] == PackageManager.PERMISSION_GRANTED
    permissionPromise?.resolve(permissionGranted) // ✅ Resolves based on actual user response
    permissionPromise = null
    return@PermissionListener true
  }
  false
}

@ReactMethod
fun requestCameraPermission(promise: Promise) {
    val permissionAwareActivity = currentActivity as? PermissionAwareActivity
    if (permissionAwareActivity == null) {
        promise.resolve(false)
        return
    }
    
    permissionPromise = promise
    permissionAwareActivity.requestPermissions(
        arrayOf(Manifest.permission.CAMERA),
        CAMERA_PERMISSION_REQUEST_CODE,
        permissionListener
    )
}

Key Benefits

  • ✅ Promise resolves with actual user response (true if granted, false if denied)
  • ✅ Works with React Native 0.81+ New Architecture (Turbo Modules)
  • ✅ Compatible with Android API 23+
  • ✅ No breaking changes to existing API
  • ✅ Eliminates need for third-party permission libraries like react-native-permissions
  • ✅ Proper memory management with cleanup in invalidate()

📱 Usage Example

import { BarcodeScanner } from '@pushpendersingh/react-native-scanner';

const checkCameraPermission = async () => {
  try {
    // First check if permission is already granted
    const hasPermission = await BarcodeScanner.hasCameraPermission();
    
    if (hasPermission) {
      console.log('Camera permission already granted');
      return true;
    }
    
    // Request permission if not granted
    const granted = await BarcodeScanner.requestCameraPermission();
    
    if (granted) {
      console.log('Camera permission granted by user');
      return true;
    } else {
      console.log('Camera permission denied by user');
      return false;
    }
  } catch (error) {
    console.error('Error checking camera permission:', error);
    return false;
  }
};

🧪 Testing

Build Verification

  • ✅ Android build successful (yarn android passes)
  • ✅ No Kotlin compilation errors
  • ✅ No TypeScript/lint errors
  • ✅ Verified on Android device (app installed and ran successfully)

Manual Testing

  • ✅ Permission dialog appears when requestCameraPermission() is called
  • ✅ Promise resolves to true when user grants permission
  • ✅ Promise resolves to false when user denies permission
  • hasCameraPermission() correctly returns permission status

Test Commands

# Build Android app
cd example && yarn android

# Lint check
yarn lint

# Type check
yarn typescript

🚀 Breaking Changes

None. This is a bug fix that makes the Android implementation work as originally intended.

Migration Guide

No migration needed. If you were using react-native-permissions as a workaround, you can now remove it:

// Before (workaround)
import { request, PERMISSIONS } from 'react-native-permissions';
const result = await request(PERMISSIONS.ANDROID.CAMERA);

// After (built-in)
import { BarcodeScanner } from '@pushpendersingh/react-native-scanner';
const granted = await BarcodeScanner.requestCameraPermission();

📄 Files Changed

  • android/src/main/java/com/reactnativescanner/ReactNativeScannerModule.kt - Core implementation
  • README.md - Added comprehensive documentation and examples
  • example/src/App.tsx - Updated to use built-in permission methods
  • example/Podfile.lock - CocoaPods dependency update (iOS)

📸 Related Issues

Fixes the issue where requestCameraPermission() on Android always returned false immediately instead of waiting for user response.

✅ Checklist

  • Code builds successfully on Android
  • Code builds successfully on iOS
  • Documentation updated in README.md
  • Example app updated to demonstrate the feature
  • No breaking changes introduced
  • Feature parity with iOS achieved
  • Proper error handling implemented
  • Memory leaks prevented with proper cleanup
  • Compatible with New Architecture

…ssionListener

Implement proper permission callback using PermissionListener and
PermissionAwareActivity for Android. Promise now resolves based on actual
user response (grant/deny) instead of immediately returning false.

Changes:
- Add PermissionListener callback to handle permission results
- Use PermissionAwareActivity for proper permission flow
- Remove react-native-permissions from example app
- Update example to use built-in permission methods
- Add comprehensive permission documentation to README
- Add proper cleanup to prevent memory leaks

Achieves feature parity with iOS. Compatible with React Native 0.81+
and Android API 23+. No breaking changes.
Copilot AI review requested due to automatic review settings September 30, 2025 20:54
@pushpender-singh-ap pushpender-singh-ap self-assigned this Sep 30, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements proper native camera permission callback mechanism for Android to achieve feature parity with iOS. The main purpose is to fix the requestCameraPermission() method so it correctly resolves based on the user's actual permission response instead of immediately returning false.

Key Changes

  • Implemented PermissionListener callback interface in Android native module with promise storage pattern
  • Updated example app to use built-in permission methods instead of react-native-permissions dependency
  • Added comprehensive documentation for permission handling APIs with usage examples

Reviewed Changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
android/src/main/java/com/pushpendersingh/reactnativescanner/ReactNativeScannerModule.kt Implements PermissionListener callback and promise storage for proper permission handling
example/src/App.tsx Removes react-native-permissions dependency and uses built-in permission methods
README.md Adds comprehensive API documentation and usage examples for permission methods

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

- Add explicit import for PermissionAwareActivity
- Replace fully qualified class name with imported reference
- Improve code readability and follow Kotlin conventions
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

- Add check to reject new requests while one is pending
- Prevent promise overwriting that causes hanging promises
- Return clear error message for concurrent requests
- Ensure all callers receive a response
- Validate that permissions array contains CAMERA permission
- Prevent incorrect permission grant due to array mismatch
- Add security check: permissions[0] == Manifest.permission.CAMERA
- Ensure only camera permission results are processed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@pushpender-singh-ap pushpender-singh-ap merged commit 40de1d1 into main Sep 30, 2025
5 of 6 checks passed
@pushpender-singh-ap pushpender-singh-ap deleted the feat/android-camera-permission-callback branch September 30, 2025 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant