我有一个基于Angular 1.6和Ionic v1的cordova应用程序。我在iOS上遇到了一个可怕的问题,我什至不知道出了什么问题。我将解释这个问题以及到目前为止我已经尝试过的方法,希望有人能对此有所启发。
问题
我们有一个简单的屏幕屏幕,您可以填写一些文本,并根据需要添加附件。对于附件,您可以:
然后可以保存记录,该记录将所有内容存储在文件系统中。或上传到服务器,服务器再将记录存储在您的设备上。
问题是,当我从库或其他任何来源中选择文件时,该应用很快崩溃。我可以添加附件并保存/上传,但是当我离开时,应用程序崩溃。这仅在iOS上发生。没有错误,没有警告,没有可调试的输出,只是崩溃了。我检查了iPhone上的崩溃日志,显然主线程被阻塞了5秒钟以上。这会导致引发看门狗违规异常。很难说是什么导致了此线程锁定,不知道。
我正在使用运行iOS 12.1的iPhone 8。值得一提的是,该应用程序可以在模拟器上正常运行,没有错误或崩溃。
到目前为止我尝试过的事情
起初,我认为我的代码可能有问题。因此,我逐行检查了每个代码文件,重构了我的JS代码并提高了代码质量。确保promise能按预期工作,解决了JSLint / TSLint警告等。
我已将所有cordova插件更新为最新版本。还删除了两个平台并添加了最新版本。他们都没有帮助。所以我想也许我缺少配置怪癖之类的东西。翻阅github文档和SO线程,找不到有用的东西。我尝试过的其他一些事情:
他们都没有工作。我已经为这个问题苦苦挣扎了两个星期。
怪异的部分
令我感到困惑的是,当我以本地开发机器为目标时,也就是说,当我将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中的Content-Security-Policy
<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上发生的事情:
一旦我使用Camera插件(cordova-camera),此应用很快就会崩溃。无论是从相机胶卷/库中选择文件还是拍照,都没关系。我只要打开相机或库,然后取消并导航即可。该应用程序崩溃。因此很明显,它与相机插件有关。
困扰我的是,正如我之前提到的,当我通过更改基本URL地址来定位本地IIS时,该应用程序运行良好。我不明白为什么这与相机使用情况有关,因为它发生在设备本地。我现在正在猜测的是,也许是由于远程URL使用HTTPS导致应用程序引发异常。但是我没有在Xcode中收到任何警告/错误,所以谁知道呢。
当然,问题不在于cordova-ios,相机插件,我的JS代码或任何安全配置(应用程序传输安全性和Content-Security-Policy)。因为该应用程序在定位我的IIS时运行良好。我想我在这里缺少什么。
答案 0 :(得分:5)
我终于找到了导致iOS应用崩溃的原因。问题出在我们的代码中,但仍然与Cordova有关,特别是File和Camera插件。
我们的项目中有一个TypeScript类,该类是很久以前由其他人开发的。此类处理了文件插件和本机文件系统中的数据访问。我们使用它来将JSON对象存储在设备上,效果很好,但仅适用于小型情况,例如保存一个或两个文件。您从服务器获取一些数据,对于每条记录,我们在文件系统上创建一个JSON文件并将其存储。当我们在循环中使用它时,发生了问题。假设您从服务器获取了100条记录,并且在一个循环中调用了save方法来存储记录。
这很好用,但是在使用Camera插件(有时甚至是其他插件,例如iCloud Document Picker)之后,应用程序立即崩溃了。我猜测是File插件或写入操作导致内存泄漏,或者应用程序的内存不足,随后访问Camera插件使应用程序崩溃。我不确定为什么在Android上一切正常,也许是因为Cordova引擎和Android文件系统不同。
尽管如此,无需在文件系统上存储JSON数据。因此,我将项目重构为使用LocalStorage。速度如此之快,它也解决了这个问题。在iOS上没有崩溃!也许可以更改用于写入文件系统的代码来解决此问题,但是无论如何都没有必要。
我很高兴终于找到答案,但是调试Cordova插件和发现内存泄漏是一场血腥的噩梦。剩下的唯一事情就是用SQLite等更可靠的东西替换LocalStorage。由于操作系统可以决定在内存/空间不足时清除数据,因此我们无法对其进行控制。现在,这完全没问题。我一直在尝试使用Ionic Storage模块,因为它使用SQLite并允许存储JSON或键/值对。但是我无法在Angular 1中使用该模块,因为我可以很好地使用其他Ionic Native模块。结案了。