以远程服务器为目标时,Cordova iOS 崩溃
Posted
技术标签:
【中文标题】以远程服务器为目标时,Cordova iOS 崩溃【英文标题】:Cordova iOS crashes when targeting remote server 【发布时间】:2018-12-18 07:51:20 【问题描述】:我有一个基于 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 发送所有内容 在 *.plist 文件中添加了 NSAppTransportSecurity 设置,并将我们的域列入白名单 修改了 Content-Security-Policy,甚至将其完全删除 已正确配置隐私说明(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 地址有什么关系?!确实很奇怪。
更新:澄清 经过更多的测试运行后,我找出了导致应用程序崩溃的原因。虽然还不清楚,但从 UX 的角度来看,这就是 iOS 上发生的情况:
一旦我使用相机插件 (cordova-camera),应用程序很快就会崩溃。如果我从相机胶卷/库中选择一个文件,或者拍照等,这并不重要。我只需打开相机或库,取消并导航离开。应用程序崩溃。很明显它与相机插件有关。
困扰我的是,正如我之前提到的,当我通过更改基本 URL 地址来定位本地 IIS 时,应用程序运行良好。我不明白为什么这与相机使用有关,因为它发生在设备本地。我现在推测的是,可能是某些原因导致应用程序抛出异常,因为远程 URL 使用 HTTPS。但是我在 Xcode 中没有收到任何警告/错误,所以谁知道呢。
当然,问题不在于 cordova-ios、相机插件、我的 JS 代码或任何安全配置(App Transport Security 和 Content-Security-Policy)。因为该应用程序在以我的 IIS 为目标时运行良好。我想我在这里遗漏了一些东西。
【问题讨论】:
您是否尝试在运行错误版本的应用程序时查看 XCode 提供的控制台? 另外,发布您在 plist 文件中包含的完整权限。 @mr5 是的,我检查了 XCode 的调试控制台,那里没有任何帮助。我收到一些线程警告说文件插件需要 X 毫秒,它应该在后台运行。但没什么好担心的,就像我说的那样,该应用程序在针对我的本地 IIS 时运行良好。我将在权限列表中更新问题。 如果您在“设置”中查看应用的权限,您是否看到这些权限已启用? 假设您已正确设置它。你等了多久?通常,会有大约 5 分钟的延迟,并且一些记录的崩溃需要符号化 dsym 文件。 【参考方案1】:我终于找到了导致 iOS 应用崩溃的原因。问题出在我们的代码中,但它仍然与 Cordova 有关,特别是文件和相机插件。
我们的项目中有一个很久以前由其他人开发的 TypeScript 类。此类使用 File 插件和本机文件系统处理数据访问。我们使用它在设备上存储 JSON 对象,这工作正常,但仅适用于保存一两个文件等小情况。您从服务器获取一些数据,并为每条记录在文件系统上创建一个 JSON 文件并存储它。当我们在循环中使用它时出现了问题。假设您从服务器返回 100 条记录,并在循环中调用 save 方法来存储记录。
这工作正常,但在使用相机插件(或有时其他插件,如 iCloud 文档选择器)后,应用程序立即无声地崩溃。我猜是文件插件或写入操作导致内存泄漏,或者应用程序内存不足,随后访问相机插件使应用程序崩溃。我不太确定为什么在 Android 上一切正常,可能是因为 Cordova 引擎和 Android 文件系统不同。
尽管如此,没有必要在文件系统上存储 JSON 数据。所以我重构了项目以使用 LocalStorage。它的速度要快得多,它也解决了这个问题。 iOS 上没有崩溃!可能是可以更改写入文件系统的代码以解决问题,但无论如何都没有必要。
我很高兴我终于弄清楚了这一点,但调试 Cordova 插件和发现内存泄漏是一场血腥的噩梦。唯一剩下的就是用 SQLite 之类的更可靠的东西替换 LocalStorage。因为操作系统可以决定在内存/空间不足时清除数据,而我们无法控制它。目前,完全没问题。我一直在尝试使用 Ionic Storage 模块,因为它使用 SQLite 并允许存储 JSON 或键/值对。但是我无法在 Angular 1 中使用该模块,这很糟糕,因为我可以很好地使用其他 Ionic Native 模块。结案。
【讨论】:
以上是关于以远程服务器为目标时,Cordova iOS 崩溃的主要内容,如果未能解决你的问题,请参考以下文章
Cordova iOS onResume 在启动和崩溃应用程序时触发
Sencha touch/cordova 应用程序在 ios8 启动时随机崩溃
Ionic2:iOS 应用程序在使用cordova-plugin-media 录制音频并再次播放时崩溃