zoontek / react-native-permissions

An unified permissions API for React Native on iOS, Android and Windows.
MIT License
4.02k stars 828 forks source link

IOS - Crash on RNPermissions lockHandler #885

Open omerts opened 2 months ago

omerts commented 2 months ago

Before submitting a new issue

Bug summary

Hello,

In Crashlytics, we are seeing the following crash when app is in the background:

          Crashed: com.apple.main-thread
0  libswiftCore.dylib             0x215928 __StringStorage.isEqualToString(to:) + 60
1  libswiftCore.dylib             0x215c64 @objc __StringStorage.isEqual(to:) + 92
2  CoreFoundation                 0x2114 -[__NSDictionaryM setObject:forKey:] + 348
3  LionWheel                      0x777c58 -[RNPermissions lockHandler:] + 300 (RNPermissions.mm:300)
4  LionWheel                      0x7782e4 -[RNPermissions request:resolve:reject:] + 341 (RNPermissions.mm:341)
5  CoreFoundation                 0x20814 __invoking___ + 148
6  CoreFoundation                 0x1f860 -[NSInvocation invoke] + 428
7  CoreFoundation                 0x961dc -[NSInvocation invokeWithTarget:] + 64
8  LionWheel                      0x828290 -[RCTModuleMethod invokeWithBridge:module:arguments:] + 587 (RCTModuleMethod.mm:587)
9  LionWheel                      0x82a394 facebook::react::invokeInner(RCTBridge*, RCTModuleData*, unsigned int, folly::dynamic const&, int, (anonymous namespace)::SchedulingContext) + 196 (RCTNativeModule.mm:196)
10 LionWheel                      0x829fe4 invocation function for block in facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int) + 247 (optional:247)
11 libdispatch.dylib              0x213c _dispatch_call_block_and_release + 32
12 libdispatch.dylib              0x3dd4 _dispatch_client_callout + 20
13 libdispatch.dylib              0x125a4 _dispatch_main_queue_drain + 988
14 libdispatch.dylib              0x121b8 _dispatch_main_queue_callback_4CF + 44
15 CoreFoundation                 0x56710 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
16 CoreFoundation                 0x53914 __CFRunLoopRun + 1996
17 CoreFoundation                 0x52cd8 CFRunLoopRunSpecific + 608
18 GraphicsServices               0x11a8 GSEventRunModal + 164
19 UIKitCore                      0x40a90c -[UIApplication _run] + 888
20 UIKitCore                      0x4be9d0 UIApplicationMain + 340
21 LionWheel                      0x739c main + 8 (main.m:8)
22 ???                            0x1b01bde4c (Missing)

image

Podfile config:

def node_require(script)
  # Resolve script with node to allow for hoisting
  require Pod::Executable.execute_command('node', ['-p',
    "require.resolve(
      '#{script}',
      {paths: [process.argv[1]]},
    )", __dir__]).strip
end

node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb')

platform :ios, '13.4'
prepare_react_native_project!

setup_permissions([
  # 'AppTrackingTransparency',
  #'Bluetooth',
  # 'Calendars',
  # 'CalendarsWriteOnly',
  'Camera',
  # 'Contacts',
  # 'FaceID',
  'LocationAccuracy',
  'LocationAlways',
  'LocationWhenInUse',
  #'MediaLibrary',
  'Microphone',
  # 'Motion',
  #'Notifications',
  'PhotoLibrary',
  # 'PhotoLibraryAddOnly',
  # 'Reminders',
  # 'Siri',
  # 'SpeechRecognition',
  # 'StoreKit',
])

Library version

4.1.5

Environment info

React Native:  0.73.6
(for some reason react-native info just stalls on my pc)

Steps to reproduce

Taken from Crashlytics, so not clear reproduction steps.

Reproducible sample code

Config:

def node_require(script)
  # Resolve script with node to allow for hoisting
  require Pod::Executable.execute_command('node', ['-p',
    "require.resolve(
      '#{script}',
      {paths: [process.argv[1]]},
    )", __dir__]).strip
end

node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb')

platform :ios, '13.4'
prepare_react_native_project!

setup_permissions([
  # 'AppTrackingTransparency',
  #'Bluetooth',
  # 'Calendars',
  # 'CalendarsWriteOnly',
  'Camera',
  # 'Contacts',
  # 'FaceID',
  'LocationAccuracy',
  'LocationAlways',
  'LocationWhenInUse',
  #'MediaLibrary',
  'Microphone',
  # 'Motion',
  #'Notifications',
  'PhotoLibrary',
  # 'PhotoLibraryAddOnly',
  # 'Reminders',
  # 'Siri',
  # 'SpeechRecognition',
  # 'StoreKit',
])

Ask for permissions using this code:

import {request, requestMultiple, PERMISSIONS} from 'react-native-permissions'
import {Platform} from 'react-native'

function isPermissionGranted(permission) {
  if (permission && typeof permission === 'object') {
    return Object.values(permission).every(
      (val) => val === 'granted' || val === 'unavailable',
    )
  }

  return permission === 'granted' || permission === 'unavailable'
}

function getCameraPermissions() {
  return Platform.OS === 'ios'
    ? PERMISSIONS.IOS.CAMERA
    : PERMISSIONS.ANDROID.CAMERA
}

function getLocationPermisison(useBackgroundLocationApproved) {
  if (Platform.OS === 'ios') {
    return [PERMISSIONS.IOS.LOCATION_ALWAYS]
  } else {
    const permissions = [
      PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
      PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION,
    ]

    // For android we show a warning about using background location which the user needs to approve according to
    // the play store guidelines
    if (useBackgroundLocationApproved) {
      permissions.push(PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION)
    }

    return permissions
  }
}

function getMicrophonePermission() {
  return Platform.OS === 'ios'
    ? PERMISSIONS.IOS.MICROPHONE
    : PERMISSIONS.ANDROID.RECORD_AUDIO
}

export const checkPermissions = async (
  useBackgroundLocationApproved = true,
  recordCalls = false,
) => {
  // Android 11 and up doesn't allow background location
  if (parseInt(Platform.constants.Release) >= 11) {
    useBackgroundLocationApproved = false
  }

  const location = await requestMultiple(
    getLocationPermisison(useBackgroundLocationApproved),
  )

  const camera = await request(getCameraPermissions())

  let voice = null

  if (recordCalls) {
    voice = await request(getMicrophonePermission())
  }

  return {
    location: isPermissionGranted(location),
    camera: isPermissionGranted(camera),
    voice: isPermissionGranted(voice),
  }
}

export default checkPermissions
kylebesser commented 2 weeks ago

I have the same issue but it is due to the LocationAlways and LocationAlwaysWhenInUse don't have the podspec file inside it.

The last version that has the podspec are 3.10.1 and I was able to run pod install. Apple is kicking my app back to me due to deprecated code using the CLLocationManager authorizationStatus. I believe now authorizationStatus is part of the CLLocationManager now. So should add something similar to the following

let manager = CLLocationManager()

manager.authorizationStatus

Not entirely sure yet if that is the fix but that is what I am currently seeing from the crash report that Apple sent to me.