NativeScript / NativeScript/ios
UI API called on a background thread: -[UIView setNeedsLayout]
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 150
- Forks
- 43
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 22
Description
Describe the bug:
We managed to update our app from NS6 to NS8 but we are getting this crash after we accessed a user's photos/videos from their device on iOS. I included our code we use to retrieve these items from the device as It could also be a factor. Please let me know if there is any other information required.
Environment:
{
"author": "www.firstview.co”,
"dependencies": {
"@nativescript-community/ui-lottie": "^4.1.2",
"@nativescript/background-http": "^5.0.2",
"@nativescript/core": "~8.1.0",
"@nativescript/firebase": "^11.1.3",
"@nativescript/local-notifications": "^5.0.3",
"@nativescript/theme": "3.0.1",
"@triniwiz/nativescript-socketio": "^5.0.1",
"@triniwiz/nativescript-toasty": "^4.1.3",
"@vue/devtools": "^5.3.4",
"moment": "^2.24.0",
"nativescript-android-utils": "^1.0.2",
"nativescript-calendar": "~3.0.0",
"nativescript-contacts": "^1.6.4",
"nativescript-dna-deviceinfo": "~3.7.1",
"nativescript-permissions": "~1.3.11",
"nativescript-sentry": "~2.0.1",
"nativescript-socketio": "~3.3.1",
"nativescript-ui-gauge": "~8.0.0",
"nativescript-ui-sidedrawer": "~10.0.1",
"nativescript-vue": "~2.9.0",
"nativescript-vue-devtools": "~1.5.1",
"nativescript-webview-interface": "~1.4.4",
"vuex": "~3.6.2"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@nativescript/android": "8.0.0",
"@nativescript/ios": "8.1.0",
"@nativescript/types": "~8.1.1",
"@nativescript/webpack": "~5.0.0",
"babel-loader": "^8.0.2",
"nativescript-vue-template-compiler": "^2.9.0",
"sass": "^1.39.2",
"typescript": "~4.0.0",
"vue-loader": "^15.4.0"
},
"main": "./app/main.js"
}
Console Log:
CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces, or set CA_ASSERT_MAIN_THREAD_TRANSACTIONS=1 to abort when an implicit transaction isn't created on a main thread.
This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
Stack:(
0 CoreAutoLayout 0x000000019a4b8dfc 09D27E78-A4B2-32D4-AB19-31802F490355 + 19964
1 CoreAutoLayout 0x000000019a4bba58 09D27E78-A4B2-32D4-AB19-31802F490355 + 31320
2 UIKitCore 0x000000018560d088 3F83EF9A-7492-3FEC-A486-5FC2A1E1B092 + 1736840
3 UIKitCore 0x00000001855e2ae8 3F83EF9A-7492-3FEC-A486-5FC2A1E1B092 + 1563368
4 QuartzCore 0x0000000186c4cc4c 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 248908
5 QuartzCore 0x0000000186c3fd40 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 195904
6 QuartzCore 0x0000000186c534a4 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 275620
7 QuartzCore 0x0000000186c5c08c 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 311436
8 QuartzCore 0x0000000186caf348 148C6302-3BF5-38DC-864C-E86D004BAFE9 + 652104
9 libsystem_pthread.dylib 0x00000001dcb20ec4
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
*** First throw call stack:
(0x183191cac 0x19a200758 0x19a4b8edc 0x19a4bba58 0x18560d088 0x1855e2ae8 0x186c4cc4c 0x186c3fd40 0x186c534a4 0x186c5c08c 0x186caf348 0x1dcb20ec4 0x1dcb23d3c 0x1dcb1f370 0x1dcb1efc0 0x1dcb1eaa4)
Xcode Log:
Main Thread Checker: UI API called on a background thread: -[UIView setNeedsLayout]
PID: 4461, TID: 1122759, Thread name: (none), Queue name: com.apple.photos.accessCallbacks, QoS: 0
Backtrace:
4 NativeScript 0x00000001025d0044 ffi_call_SYSV + 68
5 NativeScript 0x00000001025cf1d8 ffi_call_int + 968
6 NativeScript 0x0000000102571854 _ZN3tns7Interop20CallFunctionInternalERNS_10MethodCallE + 428
7 NativeScript 0x00000001024db32c _ZN3tns12ArgConverter6InvokeEN2v85LocalINS1_7ContextEEEP10objc_classNS2_INS1_6ObjectEEERNS_6V8ArgsEPKNS_10MethodMetaEb + 780
8 NativeScript 0x000000010252ebc8 _ZN3tns15MetadataBuilder12InvokeMethodEN2v85LocalINS1_7ContextEEEPKNS_10MethodMetaENS2_INS1_6ObjectEEERNS_6V8ArgsENSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEb + 88
9 NativeScript 0x000000010252e454 _ZN3tns15MetadataBuilder14MethodCallbackERKN2v820FunctionCallbackInfoINS1_5ValueEEE + 220
10 NativeScript 0x0000000102663e60 _ZN2v88internal25FunctionCallbackArguments4CallENS0_15CallHandlerInfoE + 544
11 NativeScript 0x0000000102663360 _ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0_11MaybeHandleINS0_6ObjectEEEPNS0_7IsolateENS0_6HandleINS0_10HeapObjectEEESA_NS8_INS0_20FunctionTemplateInfoEEENS8_IS4_EENS0_16BuiltinArgumentsE + 524
12 NativeScript 0x0000000102662af8 _ZN2v88internalL26Builtin_Impl_HandleApiCallENS0_16BuiltinArgumentsEPNS0_7IsolateE + 228
13 NativeScript 0x0000000102d3e3cc Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit + 108
14 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
15 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
16 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
17 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
18 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
19 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
20 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
21 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
22 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
23 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
24 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
25 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
26 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
27 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
28 NativeScript 0x0000000102cd536c Builtins_JSEntryTrampoline + 172
29 NativeScript 0x0000000102cd5004 Builtins_JSEntry + 164
30 NativeScript 0x00000001027afa70 _ZN2v88internal12_GLOBAL__N_16InvokeEPNS0_7IsolateERKNS1_12InvokeParamsE + 2532
31 NativeScript 0x00000001027af058 _ZN2v88internal9Execution4CallEPNS0_7IsolateENS0_6HandleINS0_6ObjectEEES6_iPS6_ + 216
32 NativeScript 0x000000010293ad14 _ZN2v88internal6Object23SetPropertyWithAccessorEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEE + 864
33 NativeScript 0x000000010293e804 _ZN2v88internal6Object19SetPropertyInternalEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEENS0_11StoreOriginEPb + 420
34 NativeScript 0x000000010293e584 _ZN2v88internal6Object11SetPropertyEPNS0_14LookupIt2021-10-13 10:27:21.810471+0200 mobilesafenative[4461:1122759] [reports] Main Thread Checker: UI API called on a background thread: -[UIView setNeedsLayout]
PID: 4461, TID: 1122759, Thread name: (none), Queue name: com.apple.photos.accessCallbacks, QoS: 0
Backtrace:
4 NativeScript 0x00000001025d0044 ffi_call_SYSV + 68
5 NativeScript 0x00000001025cf1d8 ffi_call_int + 968
6 NativeScript 0x0000000102571854 _ZN3tns7Interop20CallFunctionInternalERNS_10MethodCallE + 428
7 NativeScript 0x00000001024db32c _ZN3tns12ArgConverter6InvokeEN2v85LocalINS1_7ContextEEEP10objc_classNS2_INS1_6ObjectEEERNS_6V8ArgsEPKNS_10MethodMetaEb + 780
8 NativeScript 0x000000010252ebc8 _ZN3tns15MetadataBuilder12InvokeMethodEN2v85LocalINS1_7ContextEEEPKNS_10MethodMetaENS2_INS1_6ObjectEEERNS_6V8ArgsENSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEb + 88
9 NativeScript 0x000000010252e454 _ZN3tns15MetadataBuilder14MethodCallbackERKN2v820FunctionCallbackInfoINS1_5ValueEEE + 220
10 NativeScript 0x0000000102663e60 _ZN2v88internal25FunctionCallbackArguments4CallENS0_15CallHandlerInfoE + 544
11 NativeScript 0x0000000102663360 _ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0_11MaybeHandleINS0_6ObjectEEEPNS0_7IsolateENS0_6HandleINS0_10HeapObjectEEESA_NS8_INS0_20FunctionTemplateInfoEEENS8_IS4_EENS0_16BuiltinArgumentsE + 524
12 NativeScript 0x0000000102662af8 _ZN2v88internalL26Builtin_Impl_HandleApiCallENS0_16BuiltinArgumentsEPNS0_7IsolateE + 228
13 NativeScript 0x0000000102d3e3cc Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit + 108
14 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
15 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
16 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
17 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
18 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
19 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
20 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
21 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
22 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
23 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
24 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
25 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
26 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
27 NativeScript 0x0000000102cd7598 Builtins_InterpreterEntryTrampoline + 248
28 NativeScript 0x0000000102cd536c Builtins_JSEntryTrampoline + 172
29 NativeScript 0x0000000102cd5004 Builtins_JSEntry + 164
30 NativeScript 0x00000001027afa70 _ZN2v88internal12_GLOBAL__N_16InvokeEPNS0_7IsolateERKNS1_12InvokeParamsE + 2532
31 NativeScript 0x00000001027af058 _ZN2v88internal9Execution4CallEPNS0_7IsolateENS0_6HandleINS0_6ObjectEEES6_iPS6_ + 216
32 NativeScript 0x000000010293ad14 _ZN2v88internal6Object23SetPropertyWithAccessorEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEE + 864
33 NativeScript 0x000000010293e804 _ZN2v88internal6Object19SetPropertyInternalEPNS0_14LookupIteratorENS0_6HandleIS1_EENS_5MaybeINS0_11ShouldThrowEEENS0_11StoreOriginEPb + 420
34 NativeScript 0x000000010293e584 _ZN2v88internal6Object11SetPropertyEPNS0_14LookupIt
Our Service Fetching Images/Photos From the Device:
import { Device } from '@nativescript/core'
import { Sentry } from 'nativescript-sentry';
let osVersion = Device.osVersion;
@NativeClass
export class IndexMediaService {
constructor() {
}
/**
* Fetch media from device
*
* @param mediaTypes
* @returns array
*/
fetchMedia(mediaTypes) {
let getPatternFromDes = function (des, pattern, ret=0) {
let patternUrlMatch = des.match(pattern);
return (patternUrlMatch !== null) ? patternUrlMatch[ret]: '';
}
let fetchOptions:PHFetchOptions = PHFetchOptions.alloc().init();
let sortDescriptors = NSArray.arrayWithObject(
NSSortDescriptor.sortDescriptorWithKeyAscending("creationDate", false)
);
fetchOptions.sortDescriptors = sortDescriptors;
fetchOptions.predicate = NSPredicate.predicateWithFormatArgumentArray(
"mediaType = %d", NSArray.arrayWithObject(mediaTypes)
);
let fetchResult:PHFetchResult<PHAsset> = PHAsset.fetchAssetsWithOptions(fetchOptions);
let mediaOnDevice = [];
let mediaNotOnDevice = [];
let mediaCnt = 0;
fetchResult.enumerateObjectsUsingBlock((asset:PHAsset, index, stop) => {
let media = {
type: '',
mimeType: '',
sourceType: this.getSourceType(asset.sourceType),
mediaSubTypes: this.getSubType(asset.mediaSubtypes),
playbackStyle: this.getPlaybackStyle(asset.playbackStyle),
uti: '',
displayName: '',
id: '',
locallyAvailable: 'NO',
imageUri: '',
videoUri: '',
width: 0,
height: 0,
size: 0,
analysisType: '',
cplResourceType: '',
isCurrent: 'NO',
dateTaken: asset.creationDate,
dateAdded: asset.creationDate,
dateModified: asset.modificationDate,
orientation: '',
backedUp: false
};
let assetResources = PHAssetResource.assetResourcesForAsset(asset);
assetResources.enumerateObjectsUsingBlock((assetResource, ind1, stp1) => {
let type = this.getMediaType(assetResource.type);
let des = assetResource.debugDescription;
try{
if (parseInt(osVersion) >= 13) {
media.type = getPatternFromDes(des, "type:.*").replace("type: ", "");
media.uti = getPatternFromDes(des, "uti:.*").replace("uti: ", "");
media.locallyAvailable = getPatternFromDes(des, "locallyAvailable:.*").replace("locallyAvailable: ", "");
media.imageUri = getPatternFromDes(des, "file:.*").replace("file://", "");
media.videoUri = getPatternFromDes(des, "file:.*").replace("file://", "");
media.width = getPatternFromDes(des, "width:.*").replace("width: ", "");
media.height = getPatternFromDes(des, "height:.*").replace("height: ", "");
media.analysisType = getPatternFromDes(des, "analysisType:.*").replace("analysisType: ", "");
media.cplResourceType = getPatternFromDes(des, "cplResourceType:.*").replace("cplResourceType: ", "");
media.isCurrent = getPatternFromDes(des, "isCurrent:.*").replace("isCurrent: ", "");
} else if (parseInt(osVersion) >= 12 && parseInt(osVersion) < 13) {
media.type = getPatternFromDes(des, "type=(.*) size", 1);
media.uti = getPatternFromDes(des, "uti=(.*) filename", 1);
} else if (parseInt(osVersion) >= 11 && parseInt(osVersion) < 12) {
media.type = getPatternFromDes(des, "type=(.*) size", 1);
media.uti = getPatternFromDes(des, "uti=(.*) filename", 1);
}
console.log("assetResource", des)
media.displayName = assetResource.originalFilename ? assetResource.originalFilename.toString() : getPatternFromDes(des, "filename:.*").replace("filename: ", "");
media.id = assetResource.assetLocalIdentifier ? assetResource.assetLocalIdentifier.toString() : getPatternFromDes(des, "asset:.*").replace("asset: ", "")
console.log("media.id", getPatternFromDes(des, "asset:.*").replace("asset: ", ""))
media.mimeType = this.getMimeType(media.displayName) ? this.getMimeType(media.displayName) : "noMimeType"
media.size = assetResource.valueForKey('fileSize') ? assetResource.valueForKey('fileSize') : "noFileSize"
}catch(err){
let errorObj = {
errorMessage: err,
mediaObj: media
}
Sentry.captureException(err, {});
Sentry.captureMessage(JSON.stringify(errorObj))
throw errorObj
}
});
if (media.type === 'photo' && media.imageUri === '' && media.locallyAvailable === 'YES') {
const opt = PHImageRequestOptions.new();
opt.version = PHImageRequestOptionsVersion.Current;
PHImageManager.defaultManager().requestImageDataForAssetOptionsResultHandler(
asset,
opt,
(imageData, dataUTI, orientation, info) => {
try{
media.imageUri = info.objectForKey("PHImageFileURLKey").toString().replace("file://", "");
}
catch(err){
let errorObj = {
errorMessage: err,
mediaObj: media
}
console.error(errorObj)
Sentry.captureException(err, {});
Sentry.captureMessage(JSON.stringify(errorObj))
throw errorObj
}
if (media.imageUri !== '' && media.mimeType !== '') {
mediaOnDevice.push(media);
} else {
mediaNotOnDevice.push(media);
}
mediaCnt++;
}
)
} else if (media.type === 'video' && media.videoUri === '' && media.locallyAvailable === 'YES') {
let opt: PHVideoRequestOptions;
opt = PHVideoRequestOptions.new();
opt.version = PHVideoRequestOptionsVersion.Original;
PHImageManager.defaultManager().requestAVAssetForVideoOptionsResultHandler(
asset,
opt,
(avasset, audioMix, info) => {
let avurlAsset = avasset as AVURLAsset;
media.videoUri = avurlAsset.URL.toString().replace("file://", "");
if (media.videoUri !== '' && media.mimeType !== '') {
mediaOnDevice.push(media);
} else {
mediaNotOnDevice.push(media);
}
mediaCnt++;
}
)
} else {
if (media.locallyAvailable === 'YES' && media.imageUri !== '' && media.mimeType !== '') {
mediaOnDevice.push(media);
} else {
mediaNotOnDevice.push(media);
}
mediaCnt++;
}
})
return mediaOnDevice;
}
/**
* Get mime type
* @param fileName
* @returns string
*/
getMimeType(fileName) {
let extToMimes = {
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'heic': "image/heic",
'mp4': "video/mp4",
'mov': "video/quicktime",
}
let ext = fileName.toLowerCase().split('.').pop();
if (extToMimes.hasOwnProperty(ext)) {
return extToMimes[ext];
}
return '';
}
/**
* Get media type
* @param mediaId
* @returns String
*/
getMediaType(mediaId) {
switch (mediaId) {
case PHAssetMediaType.Audio:
return 'Audio'
break;
case PHAssetMediaType.Image:
return 'Image';
break;
case PHAssetMediaType.Video:
return 'Video';
default:
return 'Unkown';
break;
}
}
/**
* Get source type
* @param sourceId
* @returns string
*/
getSourceType(sourceId) {
switch (sourceId) {
case PHAssetSourceType.UserLibrary:
return 'User Library';
break;
case PHAssetSourceType.iTunesSynced:
return 'iTunes Synced'
break;
case PHAssetSourceType.CloudShared:
return 'Cloud Shared'
break;
default:
return 'None'
break;
}
}
/**
* Get media sub types
* @param subTypeId
* @returns string
*/
getSubType(subTypeId) {
switch (subTypeId) {
case PHAssetMediaSubtype.PhotoPanorama:
return 'Photo Panorama';
break;
case PHAssetMediaSubtype.PhotoHDR:
return 'Photo HDR';
break;
case PHAssetMediaSubtype.PhotoScreenshot:
return 'Photo Screenshot';
break;
case PHAssetMediaSubtype.PhotoLive:
return 'Photo Live';
break;
case PHAssetMediaSubtype.PhotoDepthEffect:
return 'Photo Depth Effect';
break;
case PHAssetMediaSubtype.VideoStreamed:
return 'Video Streamed';
break;
case PHAssetMediaSubtype.VideoHighFrameRate:
return 'Video High Frame Rate';
break;
case PHAssetMediaSubtype.VideoTimelapse:
return 'Video Timelapse';
break;
default:
return 'None';
break;
}
}
/**
* Get playback style
* @param style
* @returns string
*/
getPlaybackStyle(style) {
switch (style) {
case PHAssetPlaybackStyle.Image:
return 'Image';
break;
case PHAssetPlaybackStyle.ImageAnimated:
return 'Image Animated';
break;
case PHAssetPlaybackStyle.LivePhoto:
return 'Live Photo';
break;
case PHAssetPlaybackStyle.Video:
return 'Video';
break;
case PHAssetPlaybackStyle.VideoLooping:
return 'Video Looping';
break;
default:
return 'Unsupported'
break;
}
}
/**
* Get all video
* @returns array
*/
fetchVideos() {
// console.log('Fetch Videos');
return this.fetchMedia(PHAssetMediaType.Video);
}
/**
* Get all photos
* @returns all photos
*/
fetchPhotos() {
// console.log('Fetch Photos');
return this.fetchMedia(PHAssetMediaType.Image);
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Begin with the reported photos/videos access callback and the Main Thread Checker log, especially queue com.apple.photos.accessCallbacks and UIView setNeedsLayout. No project file, test, or concrete requested change is identified, so first reproduce the crash and trace the callback into the NativeScript iOS runtime. Done would require a confirmed reproduction and a narrowly defined regression test or fix for the background-thread UI update.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ios, javascript
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100