Cordova iOS在定位远程服务器时崩溃



我有一个基于Angular 1.6和Ionic v1构建的cordova应用程序。我在iOS上面临着一个可怕的问题,我甚至不知道出了什么问题。我将解释这个问题以及我迄今为止所做的努力,希望有人能对此有所了解。

问题
我们有一个屏幕,它是一个简单的表单,如果您愿意,您可以填写一些文本并添加附件。对于附件,您可以:

  • 用相机拍照
  • 用相机拍摄视频
  • 录制音频
  • 从您的库中选择
  • 从您的iCloud Drive(iOS)或文件系统(Android)中进行选择

然后可以保存记录,该记录将所有内容存储在文件系统中。或者上传到服务器,服务器会再次将记录存储在您的设备上。

问题是,当我从库或任何其他源中选择文件时,应用程序会在不久后意外崩溃。我可以添加附件和保存/上传,但当我离开时,应用程序会崩溃。这种情况只在iOS上发生。没有错误,没有警告,没有可调试的输出,只是崩溃。我检查了我iPhone上的崩溃日志,显然主线程被阻塞了5秒钟以上。这会引发看门狗违规异常。很难说是什么导致了线程锁定,不知道。

我使用的是运行iOS 12.1的iPhone 8。值得一提的是,该应用程序在模拟器上运行良好,没有错误或崩溃。

到目前为止我尝试了什么
起初,我认为我的代码可能有问题。因此,我逐行查看了每一个代码文件,重构了我的JS代码,提高了代码质量。确保承诺按预期工作,解决JSLint/TSLint警告等

我已经将所有cordova插件更新到了最新版本。还删除了这两个平台并添加了最新版本。他们都没帮上忙。所以我想也许我错过了一个配置怪癖什么的。翻阅github文档和SO线程,找不到任何有用的东西。我尝试过的其他一些东西:

  • 在我们的生产服务器上禁用HTTPS,并通过HTTP发送所有内容
  • NSAppTransportSecurity设置添加到*.plist文件中,并将我们的域列入白名单
  • 修补了内容安全策略,甚至将其完全删除
  • 隐私说明配置正确(NSCameraUsage等)

它们都不起作用。我已经为这个问题纠结了两个星期了。

奇怪的部分
让我困惑的是,当我以本地开发机器为目标时,也就是说,当我为API调用设置基本URL以指向本地IIS时,应用程序运行得非常好。没有错误,没有崩溃。

但当我以远程服务器为目标时,当我尝试使用附件(相机、iCloud等)时,应用程序会崩溃。我不知道我在这里缺少了什么。我的机器和我们的远程服务器没有区别。两者运行完全相同的软件,相同的配置,移动应用程序是相同的版本,运行在相同的设备上。

所以我可以肯定的是,这个问题与我的应用程序代码或Cordova及其插件无关。当针对我的本地IIS时,同样的构建非常有效。

我的应用程序已经在生产中,现在需要修复。这让我很生气,我已经试过了我能想到的一切,但仍然没有运气。有人遇到过类似的问题吗?感谢您的帮助。

我没有被授权分享我的代码,正如我所说,代码没有错,当针对我的本地IIS时,它绝对可以正常工作。但为了供您参考,这里有一些关于我的项目的信息。

Config.xml中的首选项

<preference name="SplashScreen" value="screen" />
<preference name="windows-target-version" value="10.0" />
<preference name="AndroidPersistentFileLocation" value="Internal" />
<preference name="iosPersistentFileLocation" value="Library" />
<preference name="webviewbounce" value="false" />
<preference name="UIWebViewBounce" value="false" />
<preference name="DisallowOverscroll" value="true" />
<preference name="BackupWebStorage" value="local" />

Cordova插件

<plugin name="cordova-plugin-geolocation" spec="^2.4.3">
<variable name="GEOLOCATION_USAGE_DESCRIPTION" value="Location access allows you to capture your geolocation information on to your records." />
</plugin>
<plugin name="cordova-plugin-device" spec="^1.1.7" />
<plugin name="cordova-plugin-whitelist" spec="^1.3.3" />
<plugin name="cordova-plugin-app-icon-changer" spec="^1.0.0" />
<plugin name="es6-promise-plugin" spec="^4.2.2" />
<plugin name="cordova-plugin-ios-camera-permissions" spec="^1.2.0">
<variable name="CAMERA_USAGE_DESCRIPTION" value="Camera access allows you to capture and attach photos that you take to your records." />
<variable name="MICROPHONE_USAGE_DESCRIPTION" value="Microphone access allows you to capture voice information to your records." />
<variable name="PHOTOLIBRARY_ADD_USAGE_DESCRIPTION" value="Photo library access allows you to upload your photos and media files to your records." />
<variable name="PHOTOLIBRARY_USAGE_DESCRIPTION" value="Photo library access allows you to upload your photos and media files to your records." />
</plugin>
<plugin name="cordova-plugin-android-fingerprint-auth" spec="^1.4.1" />
<plugin name="cordova-plugin-inappbrowser" spec="^3.0.0" />
<plugin name="cordova-plugin-filechooser" spec="1.1.0" />
<plugin name="cordova-plugin-crosswalk-webview" spec="2.4.0">
<variable name="XWALK_VERSION" value="23+" />
<variable name="XWALK_LITEVERSION" value="xwalk_core_library_canary:17+" />
<variable name="XWALK_COMMANDLINE" value="--disable-pull-to-refresh-effect" />
<variable name="XWALK_MODE" value="embedded" />
<variable name="XWALK_MULTIPLEAPK" value="true" />
</plugin>
<plugin name="cordova-plugin-statusbar" spec="2.4.2" />
<plugin name="cordova-plugin-add-swift-support" spec="1.7.2" />
<plugin name="cordova-plugin-touch-id" spec="3.4.0">
<variable name="FACEID_USAGE_DESCRIPTION" value="OnRecord would like to access your touch ID to let you log in securely." />
</plugin>
<plugin name="cordova-plugin-media-playback" spec="1.0.2-dev5" />
<plugin name="cordova-plugin-documentpicker" spec="1.0.0" />
<plugin name="cordova-plugin-file" spec="6.0.1" />
<plugin name="cordova-plugin-file-transfer" spec="1.7.1" />
<plugin name="cordova-plugin-media-capture" spec="3.0.2" />
<plugin name="cordova-plugin-camera" spec="4.0.3" />

index.html中的内容安全策略

<meta http-equiv="Content-Security-Policy" content="default-src 'self' gap://ready ms-appdata file://* *; img-src 'self' content: android-webview-video-poster: data: *; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://maps.googleapis.com https://maps.gstatic.com; media-src *; connect-src *">

应用程序传输安全策略

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSAllowsLocalNetworking</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>your.domain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>1.0</string>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>

隐私说明(权限)

<key>NSFaceIDUsageDescription</key>
<string>This app would like to access your touch ID to let you log in securely.</string>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app would like to access your location to let you track your records.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs write-access to photo library</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs read/write-access photo library access</string>

如果您需要更多信息或任何进一步的解释,请告诉我。我尽力把这个问题描述得最好。概括一下:

该应用程序在针对我的本地机器时运行完美,但在针对我们的远程服务器时崩溃。困扰我的是,这不应该与我的应用程序有任何关系。相机插件,从不同来源选择文件等都发生在设备的本地,这与我的基本API地址有什么关系?!确实很奇怪。

更新:澄清
经过更多的测试运行,我已经找出了导致应用程序崩溃的原因。虽然还不清楚,但从用户体验的角度来看,这就是iOS上发生的事情:

我一使用相机插件(cordova相机),应用程序不久就会崩溃。无论我是从相机胶卷/库中选择一个文件,还是拍照等,都无关紧要。我只需打开相机或库,取消并导航离开。应用程序崩溃。很明显,这与相机插件有关。

困扰我的是,正如我之前提到的,当我通过更改基本URL地址来定位本地IIS时,该应用程序运行良好。我不明白为什么这与相机的使用有关,因为它发生在设备的本地。我现在猜测的是,可能是某种原因导致应用程序抛出异常,因为远程URL使用HTTPS。但我在Xcode中没有收到任何警告/错误,谁知道呢。

当然,问题不在于cordova ios、相机插件、我的JS代码或任何安全配置(应用程序传输安全和内容安全策略)。因为该应用程序在针对我的IIS时运行良好。我想我错过了什么。

我终于找到了导致iOS应用程序崩溃的原因。问题出在我们的代码中,但仍然与Cordova有关,特别是文件和相机插件。

我们的项目中有一个TypeScript类,它是很久以前由其他人开发的。这个类处理对文件插件和本机文件系统的数据访问。我们使用它在设备上存储JSON对象,它运行良好,但仅适用于保存一两个文件等小情况。你从服务器上获取一些数据,对于每条记录,我们在文件系统上创建一个JSON文件并存储它。当我们在循环中使用它时,出现了问题。假设您从服务器取回100条记录,然后在一个循环中调用save方法来存储这些记录。

这很好,但在使用Camera插件(或有时使用iCloud Document Picker等其他插件)后,应用程序立即崩溃。我猜File插件或写入操作导致了内存泄漏,或者应用程序内存不足,随后访问Camera插件导致应用程序崩溃。我不太清楚为什么Android上一切都很好,也许是因为Cordova引擎和Android文件系统不同。

然而,不需要在文件系统上存储JSON数据。所以我重构了这个项目,改为使用LocalStorage。它速度快得多,也解决了问题。iOS上没有崩溃!可能是可以更改写入文件系统的代码来解决问题,但无论如何都没有必要。

我很高兴我终于明白了这一点,但调试Cordova插件和发现内存泄漏是一场血腥的噩梦。剩下的就是用更可靠的东西来代替LocalStorage,比如SQLite。因为操作系统可以在内存/空间不足时决定清除数据,而我们无法控制它。目前,一切都很好。我一直在尝试使用Ionic Storage模块,因为它使用SQLite并允许存储JSON或键/值对。但我还没能在Angular 1中使用这个模块,这很麻烦,因为我可以很好地使用其他Ionic Native模块。案件结案。

最新更新