Skip to Content
Product Information

Hybrid Application Toolkit – apps for iOS: switching to WKWebView

Update 3 July 2020: Cloud Build Service now includes the required dependencies and fixes.

Update 19 March 2020: Added additional workaround for offline apps.

For those developing hybrid cross-platform apps with SAP Web IDE Full-Stack, by making use of the Hybrid Application Toolkit extension and SAP Mobile Services, there is an important update for the iOS platform.

But before I jump into the details, I want to remind you about the following:

When you start developing a new mobile app, we strongly recommend that you consider developing this with either MDK (Mobile Development Kit) for cross platform applications, or our native SDKs (SAP Cloud Platform SDK for iOS or SAP Cloud Platform SDK for Android).

Some background on the WebView components

Cordova for iOS has been using the iOS platform component UIWebView for a long time. UIWebView was originally introduced in iOS 2.0. This component is used by Cordova to display web content in a native app. This is the crucial part that makes an app a hybrid app – part native code, part web app.

At WWDC 2018 (June 2018), Apple introduced the iOS 12 SDK beta, in which this component was deprecated. It took quite a bit of time for the open source community to adopt the alternative component named WKWebView. There are plenty of reasons for this to find online, so I’ll not go into details here. Note that Apple has not removed UIWebView until now, and will not do this any time soon.

However, in December 2019 Apple made an announcement that impacts apps published in Apple’s iOS App Store:

  • The App Store will no longer accept new apps using UIWebView as of April 2020
  • The App Store will no longer accept app updates using UIWebView as of December 2020

My expectation is that Apple will remove UIWebView in 2021 with the introduction of iOS 15. I can be wrong here; but this seems the most logical at this point.

Impact for your hybrid app

What does this mean for you as a developer, having used Hybrid Application Toolkit to build iOS apps ?

  1. If you are planning to publish a new app, you should first of all consider using MDK.
  2. If you still go ahead with a hybrid app, then this iOS app must use WKWebView from April 2020 onwards, BUT ONLY WHEN YOU INTEND TO PUBLISH THE APP IN THE PUBLIC APP STORE. If you intend to distribute your app within your enterprise, using a mobile device management solution, then you are not tied to this deadline.
  3. If you have an existing app in the AppStore, you have until December 2020 to switch to WKWebView for publishing updates.
  4. Speculative: when Apple rolls out iOS 15 in 2021, your UIWebView based apps will not work anymore.

How to ensure your app uses WKWebView

New apps

For new mobile hybrid apps created in SAP Web IDE Full-Stack with Hybrid Application Toolkit, we have updated our template code to ensure WKWebView is used by default. As soon as you ‘mobile-enable’ your project, it will automatically be configured for this. Once you rebuild the app with our Cloud Build Service, the resulting app uses WKWebView.

Existing app

For existing apps, you will have to modify your code and configuration settings, and trigger a new build with our Cloud Build Service. Steps:

  1. Add the cordova plugin “cordova-plugin-wkwebview-engine” to your project. The easiest way to do this is by opening the project context menu (right-click on the project) and select Mobile > Select Cordova Plugins. Then search for the above mentioned plugin in the list of publicly available plugins, add it, and save the selection.
  2. Optionally, as our Cloud Build Service should be adding this automatically as of 3 July 2020 (you can download the XCode project and verify yourself if you are in doubts):
    1. Add
      <preference name="WKWebViewOnly" value="true" />​
      
      

      in config.xml to ensure UIWebView is completely removed at compile-time.

    2. Ensure cordova ios 5.1.1 or later is used.
    3. In config.xml, add
      <preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine" />
      <feature name="CDVWKWebViewEngine">
          <param name="ios-package" value="CDVWKWebViewEngine" />
      </feature>
      ​

Offline Apps

Update 3 July 2020: this fix is already available in our Cloud Build Service. You can skip this.

For offline apps, either new, or existing ones, there is an additional change required. This is a temporary workaround until the Mobile SDK (Kapsel) is updated.

In this blog post I’ve provided an example of how to initialise an offline store. In the success callback we use the sap.OData.applyHttpClient() to ensure offline OData calls use datajs. This will also enable Xhook for handling calls to fetch local media files. However, this piece has an issue and a fix will be provided soon. Until our Cloud Build Service is updated with this fix, please disable Xhook by calling sap.Xhook.disable().

var openStoreSuccessCallback = function() {
    sap.OData.applyHttpClient();  //Offline OData calls can now be made against datajs.
    sap.Xhook.disable(); // temporary workaround to ensure the offline app can work in WKWebView
    sap.hybrid.startApp();
}

Improvements coming with WKWebView

Noticeable changes with the WebView are in the area of (perceived) performance:

  • Faster JavaScript engine, using Nitro.
  • WKWebView runs out of process.
  • JavaScript is handled asynchronously, eliminating blocking calls.
  • Improvements in handling touch events (less delay).

Challenges coming with WKWebView

Besides improvements, there are unfortunately also some issues introduced. The main issue is that WKWebView comes with stricter cross origin resource sharing rules (CORS). To resolve some of these, we are making use of the Kapsel native plugin “AuthProxy”.

When debugging the app using Safari (remote debug), you will not see the traffic going through native code. In case you want to debug these calls (e.g. OData queries), it is recommended to use the Network Traces feature in the SAP Mobile Services cockpit.

When can you make the switch?

You can switch to WKWebView now and start testing. To comply with the App Store submission guidelines for new apps set by Apple, you need to use Cordova for iOS 5.1.1 or later in order to completely remove any reference to UIWebView. This update has been released in the Mobile SDK last month and is from 3 July 2020 available on our Cloud Build Service.

In case you run into problems

We have thoroughly tested the apps generated with Hybrid Application Toolkit and did not find issues after making the switch to WKWebView. However, your apps might make use of features (or plugins) that are affected by this change. Please ensure you test your apps before rolling them out to your users.

In case you are facing issues, please raise a support ticket for component CA-WDE-MOB.

Thanks,
Ludo Noens

 

6 Comments
You must be Logged on to comment or reply to a post.
  • Hello Ludo,

    Thank you for this blog. I have created an OSS Note about Custom Fiori Client iOS deploy and they sent me your blog.

    I created a custom fiori client project on WebIDE FullStack. I created signing profiles for ios and android. I have no problem about android app. But i cant deploy my ipa file to App Store Connect. Reason is UIWebView.

    ITMS-90809: Deprecated API Usage – New apps that use UIWebView are no longer accepted. Instead, use WKWebView for improved security and reliability.

    When i created new custom fiori client app and got a cloud build, problem is not solved.
    I changed existing project. I followed the steps you specified.

    After cloud build, i saved xcode project. I shared config.xml documents at end of my comment.

    I tried to deploy my app to App Store Connect again and got the same error again. The problem continues.

    How we can solve this problem? can you help us?

    Here is mine config.xml on WebIDE

    <?xml version="1.0" encoding="utf-8"?>
    <!-- Change the App Name, App Version, App Description and Min OS Versions in the 
         build wizard UI rather than manually modifying their values here. -->
    <!-- Do not change the widget "id" value here. -->
    <widget xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" id="com.turktraktor.fioriclient4" version="1.4">
    	<name>TurkTraktorFioriClient4</name>
    	<author/>
    	<description>TurkTraktorCustomFioriClientApp</description>
    	<content src="index.html"/>
    	<access origin="*"/>
    	<allow-intent href="http://*/*"/>
    	<allow-intent href="https://*/*"/>
    	<allow-intent href="tel:*"/>
    	<allow-intent href="sms:*"/>
    	<allow-intent href="mailto:*"/>
    	<allow-intent href="geo:*"/>
    	<allow-navigation href="*"/>
    	<preference name="AutoHideSplashScreen" value="true"/>
    	<preference name="FadeSplashScreen" value="false"/>
    	<preference name="helpUrl" value="https://help.sap.com/doc/d55f83e12e4b40779158fbaf08fe0f14/1.9/en-US/index.html"/>
    	<preference name="trustUserCertificates" value="true"/>
    	<preference name="cleartextTrafficPermitted" value="true"/>
    	<preference name="xwalkVersion" value="23+"/>
    	<preference name="WKWebViewOnly" value="true"/>
    	<preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine"/>
    	<feature name="CDVWKWebViewEngine">
    		<param name="ios-package" value="CDVWKWebViewEngine"/>
    	</feature>
    	<!-- Do not modify the spec attribute values. Cloud build service will replace them with the platform versions of the available build stacks. -->
    	<engine name="ios" spec="*"/>
    	<engine name="android" spec="*"/>
    	<platform name="android">
    		<allow-intent href="market:*"/>
    		<allow-intent href="sapauthenticator:*"/>
    		<preference name="android-minSdkVersion" value="21"/>
    		<preference name="android-targetSdkVersion" value="28"/>
    		<preference name="Orientation" value="default"/>
    		<preference name="CustomURLSchemePluginClearsAndroidIntent" value="true"/>
    		<!-- Do not modify the content of these icon & splash tags. Instead, upload your images from the cloud build wizard. -->
    		<icon src="res/android/drawable/icon.png"/>
    		<icon density="hdpi" src="res/android/drawable/icon.png"/>
    		<icon density="hdpi" src="res/android/drawable-hdpi/icon.png"/>
    		<icon density="ldpi" src="res/android/drawable-ldpi/icon.png"/>
    		<icon density="mdpi" src="res/android/drawable-mdpi/icon.png"/>
    		<icon density="xhdpi" src="res/android/drawable-xhdpi/icon.png"/>
    		<icon density="xxhdpi" src="res/android/drawable-xxhdpi/icon.png"/>
    		<icon density="xxxhdpi" src="res/android/drawable-xxxhdpi/icon.png"/>
    		<splash density="land-hdpi" src="res/screen/android/splash-land-hdpi.png"/>
    		<splash density="land-ldpi" src="res/screen/android/splash-land-ldpi.png"/>
    		<splash density="land-mdpi" src="res/screen/android/splash-land-mdpi.png"/>
    		<splash density="land-xhdpi" src="res/screen/android/splash-land-xhdpi.png"/>
    		<splash density="land-xxhdpi" src="res/screen/android/splash-land-xxhdpi.png"/>
    		<splash density="land-xxxhdpi" src="res/screen/android/splash-land-xxxhdpi.png"/>
    		<splash density="port-hdpi" src="res/screen/android/splash-port-hdpi.png"/>
    		<splash density="port-ldpi" src="res/screen/android/splash-port-ldpi.png"/>
    		<splash density="port-mdpi" src="res/screen/android/splash-port-mdpi.png"/>
    		<splash density="port-xhdpi" src="res/screen/android/splash-port-xhdpi.png"/>
    		<splash density="port-xxhdpi" src="res/screen/android/splash-port-xxhdpi.png"/>
    		<splash density="port-xxxhdpi" src="res/screen/android/splash-port-xxxhdpi.png"/>
    	</platform>
    	<platform name="ios">
    		<!-- Do not modify the content of these icon & splash tags. Instead, upload your images from the cloud build wizard. -->
    		<icon height="40" src="res/icon/ios/icon-40.png" width="40"/>
    		<icon height="80" src="res/icon/ios/icon-40@2x.png" width="80"/>
    		<icon height="50" src="res/icon/ios/icon-50.png" width="50"/>
    		<icon height="100" src="res/icon/ios/icon-50@2x.png" width="100"/>
    		<icon height="60" src="res/icon/ios/icon-60.png" width="60"/>
    		<icon height="120" src="res/icon/ios/icon-60@2x.png" width="120"/>
    		<icon height="72" src="res/icon/ios/icon-72.png" width="72"/>
    		<icon height="144" src="res/icon/ios/icon-72@2x.png" width="144"/>
    		<icon height="76" src="res/icon/ios/icon-76.png" width="76"/>
    		<icon height="152" src="res/icon/ios/icon-76@2x.png" width="152"/>
    		<icon height="29" src="res/icon/ios/icon-small.png" width="29"/>
    		<icon height="58" src="res/icon/ios/icon-small@2x.png" width="58"/>
    		<icon height="57" src="res/icon/ios/icon.png" width="57"/>
    		<icon height="114" src="res/icon/ios/icon@2x.png" width="114"/>
    		<icon height="120" src="res/icon/ios/icon-Small-40@3x.png" width="120"/>
    		<icon height="180" src="res/icon/ios/icon-60@3x.png" width="180"/>
    		<icon height="87" src="res/icon/ios/icon-Small@3x.png" width="87"/>
    		<icon height="167" src="res/icon/ios/icon-83.5@2x.png" width="167"/>
    		<splash height="480" src="res/screen/ios/Default~iphone.png" width="320"/>
    		<splash height="960" src="res/screen/ios/Default@2x~iphone.png" width="640"/>
    		<splash height="1024" src="res/screen/ios/Default-Portrait~ipad.png" width="768"/>
    		<splash height="2048" src="res/screen/ios/Default-Portrait@2x~ipad.png" width="1536"/>
    		<splash height="768" src="res/screen/ios/Default-Landscape~ipad.png" width="1024"/>
    		<splash height="1536" src="res/screen/ios/Default-Landscape@2x~ipad.png" width="2048"/>
    		<splash height="1136" src="res/screen/ios/Default-568h@2x~iphone.png" width="640"/>
    		<splash height="1334" src="res/screen/ios/Default-667h@2x.png" width="750"/>
    		<splash height="750" src="res/screen/ios/Default-Landscape@2x~iphone6.png" width="1334"/>
    		<splash height="2208" src="res/screen/ios/Default-Portrait-736h@3x.png" width="1242"/>
    		<splash height="1242" src="res/screen/ios/Default-Landscape-736h@3x.png" width="2208"/>
    		<splash height="2732" src="res/screen/ios/Default-iPadPro-Portrait@2x~ipad.png" width="2048"/>
    		<splash height="2048" src="res/screen/ios/Default-iPadPro-Landscape@2x~ipad.png" width="2732"/>
    		<allow-intent href="itms:*"/>
    		<allow-intent href="itms-apps:*"/>
    		<preference name="Orientation" value="all"/>
    		<preference name="deployment-target" value="12.4.1"/>
    		<preference name="StatusBarOverlaysWebView" value="false"/>
    		<preference name="StatusBarStyle" value="default"/>
    		<preference name="StatusBarBackgroundColor" value="#FFFFFF"/>
    		<!-- iOS Split View support  -->
    		<edit-config file="*-Info.plist" mode="merge" target="UIRequiresFullScreen">
    			<false/>
    		</edit-config>
    		<edit-config file="*-Info.plist" mode="merge" target="UILaunchStoryboardName">
    			<string>CDVLaunchScreen</string>
    		</edit-config>
    		<!-- Required by Camera and Barcode plugins -->
    		<edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access the camera.</string>
    		</edit-config>
    		<!-- Required by Camera plugin -->
    		<edit-config target="NSPhotoLibraryUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access the library.</string>
    		</edit-config>
    		<!-- Required by Camera and Geolocation plugins -->
    		<edit-config target="NSLocationWhenInUseUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access location.</string>
    		</edit-config>
    		<!-- Required by Voice Recording plugin -->
    		<edit-config target="NSMicrophoneUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access the microphone.</string>
    		</edit-config>
    		<!-- Required by Camera and Geolocation plugins -->
    		<edit-config target="NSLocationAlwaysUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access location.</string>
    		</edit-config>
    		<!-- Required by Camera plugin -->
    		<edit-config target="NSPhotoLibraryAddUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access the library.</string>
    		</edit-config>
    		<!-- Required by Contacts plugin -->
    		<edit-config target="NSContactsUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access contacts.</string>
    		</edit-config>
    		<!-- Required by Calendar plugin -->
    		<edit-config target="NSCalendarsUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access the calendar.</string>
    		</edit-config>
    		<!-- Required by Logon plugin -->
    		<edit-config target="NSFaceIDUsageDescription" file="*-Info.plist" mode="merge">
    			<string>App would like to access Face ID for authentication.</string>
    		</edit-config>
    		<!-- Required for certificate import -->
    		<edit-config file="*-Info.plist" mode="merge" target="LSSupportsOpeningDocumentsInPlace">
    			<false/>
    		</edit-config>
    	</platform>
    	<!-- The latest available version of Kapsel and default Cordova plugins in Cloud Build Service will -->
    	<!-- be installed, i.e. their "spec" attribute values, if added, will be ignored. -->
    	<plugin name="kapsel-plugin-apppreferences"/>
    	<plugin name="kapsel-plugin-authproxy"/>
    	<plugin name="kapsel-plugin-corelibs"/>
    	<plugin name="kapsel-plugin-encryptedstorage"/>
    	<plugin name="kapsel-plugin-fioriclient"/>
    	<plugin name="kapsel-plugin-i18n"/>
    	<plugin name="kapsel-plugin-logger"/>
    	<plugin name="kapsel-plugin-logon"/>
    	<plugin name="kapsel-plugin-settings"/>
    	<plugin name="kapsel-plugin-keychaincertprovider"/>
    	<plugin name="kapsel-plugin-attachmentviewer"/>
    	<plugin name="kapsel-plugin-cdsprovider"/>
    	<plugin name="kapsel-plugin-calendar"/>
    	<plugin name="kapsel-plugin-inappbrowser"/>
    	<plugin name="kapsel-plugin-barcodescanner"/>
    	<plugin name="kapsel-plugin-cachemanager"/>
    	<plugin name="kapsel-plugin-consent"/>
    	<plugin name="kapsel-plugin-online"/>
    	<plugin name="kapsel-plugin-toolbar"/>
    	<plugin name="kapsel-plugin-usage"/>
    	<plugin name="kapsel-plugin-voicerecording"/>
    	<plugin name="cordova-plugin-device"/>
    	<plugin name="cordova-plugin-splashscreen"/>
    	<plugin name="cordova-plugin-file"/>
    	<plugin name="cordova-plugin-camera"/>
    	<plugin name="cordova-plugin-network-information"/>
    	<plugin name="cordova-plugin-geolocation"/>
    	<plugin name="cordova-plugin-statusbar"/>
    	<plugin name="cordova-plugin-dialogs"/>
    	<plugin name="cordova-plugin-whitelist"/>
    	<plugin name="de.appplant.cordova.plugin.printer"/>
    	<plugin name="cordova-plugin-privacyscreen"/>
    	<plugin name="cordova-plugin-screen-orientation"/>
    	<plugin name="cordova-plugin-wkwebview-engine" spec="1.2.1"/>
    	<plugin name="es6-promise-plugin"/>
    	<plugin name="cordova-plugin-bluetooth-serial" spec="0.4.7"/>
    </widget>

     

    XCode>ProjectName>config.xml is same with WebIDE.

    XCode>ProjectName>Staging>config.xml (I can see which I had inserted previously.)

    <?xml version='1.0' encoding='utf-8'?>
    <widget id="com.turktraktor.fioriclient4" ios-CFBundleVersion="1.4" version="1.4" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
        <feature name="LocalStorage">
            <param name="ios-package" value="CDVLocalStorage" />
        </feature>
        <feature name="Console">
            <param name="ios-package" value="CDVLogger" />
            <param name="onload" value="true" />
        </feature>
        <feature name="HandleOpenUrl">
            <param name="ios-package" value="CDVHandleOpenURL" />
            <param name="onload" value="true" />
        </feature>
        <feature name="IntentAndNavigationFilter">
            <param name="ios-package" value="CDVIntentAndNavigationFilter" />
            <param name="onload" value="true" />
        </feature>
        <feature name="GestureHandler">
            <param name="ios-package" value="CDVGestureHandler" />
            <param name="onload" value="true" />
        </feature>
        <feature name="BluetoothSerial">
            <param name="ios-package" onload="true" value="MEGBluetoothSerial" />
        </feature>
        <feature name="AppPreferences">
            <param name="ios-package" value="SMPAppPreferencesPlugin" />
        </feature>
        <feature name="i18n">
            <param name="ios-package" value="SMPI18nPlugin" />
        </feature>
        <feature name="AuthProxy">
            <param name="ios-package" value="SMPAuthProxyPlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="MAFLogonCoreCDVPluginJS">
            <param name="ios-package" value="MAFLogonCoreCDVPlugin" />
        </feature>
        <feature name="EncryptedStorage">
            <param name="ios-package" value="SMPEncryptedStoragePlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="FioriClient">
            <param name="ios-package" value="SMPFioriClientPlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="SMPSettingsExchangePlugin" onload="true">
            <param name="ios-package" value="SMPSettingsExchangePlugin" />
        </feature>
        <feature name="Usage">
            <param name="ios-package" value="SMPUsagePlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="VoiceRecording">
            <param name="ios-package" value="SMPVoiceRecordingPlugin" />
        </feature>
        <feature name="Camera">
            <param name="ios-package" value="CDVCamera" />
        </feature>
        <feature name="Device">
            <param name="ios-package" value="CDVDevice" />
        </feature>
        <feature name="Notification">
            <param name="ios-package" value="CDVNotification" />
        </feature>
        <feature name="File">
            <param name="ios-package" value="CDVFile" />
            <param name="onload" value="true" />
        </feature>
        <feature name="Geolocation">
            <param name="ios-package" value="CDVLocation" />
        </feature>
        <feature name="NetworkStatus">
            <param name="ios-package" value="CDVConnection" />
        </feature>
        <feature name="CDVOrientation">
            <param name="ios-package" value="CDVOrientation" />
        </feature>
        <feature name="SplashScreen">
            <param name="ios-package" value="CDVSplashScreen" />
            <param name="onload" value="true" />
        </feature>
        <feature name="StatusBar">
            <param name="ios-package" value="CDVStatusBar" />
            <param name="onload" value="true" />
        </feature>
        <feature name="CDVWKWebViewEngine">
            <param name="ios-package" value="CDVWKWebViewEngine" />
        </feature>
        <feature name="Printer">
            <param name="ios-package" value="SMPPrintPlugin" />
        </feature>
        <feature name="InAppBrowser">
            <param name="ios-package" value="CDVInAppBrowser" />
            <param name="onload" value="true" />
        </feature>
        <feature name="UIInAppBrowser">
            <param name="ios-package" value="CDVUIInAppBrowser" />
            <param name="onload" value="true" />
        </feature>
        <feature name="WKInAppBrowser">
            <param name="ios-package" value="CDVWKInAppBrowser" />
            <param name="onload" value="true" />
        </feature>
        <feature name="AttachmentHandler">
            <param name="ios-package" value="SMPAttachmentViewerPlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="BarcodeScanner">
            <param name="ios-package" value="CDVBarcodeScanner" />
        </feature>
        <feature name="Online">
            <param name="ios-package" value="SMPOnlinePlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="CacheManager">
            <param name="ios-package" value="SMPCacheManagerPlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="Calendar">
            <param name="ios-package" value="SMPCalendarPlugin" />
        </feature>
        <feature name="KeychainCertProvider">
            <param name="ios-package" value="SMPKeychainCertProviderPlugin" />
            <param name="onload" value="true" />
        </feature>
        <feature name="Logging">
            <param name="ios-package" value="SMPLoggerPlugin" />
        </feature>
        <feature name="toolbar">
            <param name="ios-package" value="SMPToolbarPlugin" />
            <param name="onload" value="true" />
        </feature>
        <name>TurkTraktorFioriClient4</name>
        <author />
        <description>TurkTraktorCustomFioriClientApp</description>
        <content src="index.html" />
        <access origin="*" />
        <allow-intent href="http://*/*" />
        <allow-intent href="https://*/*" />
        <allow-intent href="tel:*" />
        <allow-intent href="sms:*" />
        <allow-intent href="mailto:*" />
        <allow-intent href="geo:*" />
        <allow-navigation href="*" />
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
        <edit-config file="*-Info.plist" mode="merge" target="UIRequiresFullScreen">
            <false />
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="UILaunchStoryboardName">
            <string>CDVLaunchScreen</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSCameraUsageDescription">
            <string>App would like to access the camera.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSPhotoLibraryUsageDescription">
            <string>App would like to access the library.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSLocationWhenInUseUsageDescription">
            <string>App would like to access location.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSMicrophoneUsageDescription">
            <string>App would like to access the microphone.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSLocationAlwaysUsageDescription">
            <string>App would like to access location.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSPhotoLibraryAddUsageDescription">
            <string>App would like to access the library.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSContactsUsageDescription">
            <string>App would like to access contacts.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSCalendarsUsageDescription">
            <string>App would like to access the calendar.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="NSFaceIDUsageDescription">
            <string>App would like to access Face ID for authentication.</string>
        </edit-config>
        <edit-config file="*-Info.plist" mode="merge" target="LSSupportsOpeningDocumentsInPlace">
            <false />
        </edit-config>
        <icon height="20" src="res/icon/ios/icon-20.png" width="20" />
        <icon height="40" src="res/icon/ios/icon-40.png" width="40" />
        <icon height="80" src="res/icon/ios/icon-40@2x.png" width="80" />
        <icon height="50" src="res/icon/ios/icon-50.png" width="50" />
        <icon height="100" src="res/icon/ios/icon-50@2x.png" width="100" />
        <icon height="60" src="res/icon/ios/icon-60.png" width="60" />
        <icon height="120" src="res/icon/ios/icon-60@2x.png" width="120" />
        <icon height="72" src="res/icon/ios/icon-72.png" width="72" />
        <icon height="144" src="res/icon/ios/icon-72@2x.png" width="144" />
        <icon height="76" src="res/icon/ios/icon-76.png" width="76" />
        <icon height="152" src="res/icon/ios/icon-76@2x.png" width="152" />
        <icon height="29" src="res/icon/ios/icon-small.png" width="29" />
        <icon height="58" src="res/icon/ios/icon-small@2x.png" width="58" />
        <icon height="57" src="res/icon/ios/icon.png" width="57" />
        <icon height="114" src="res/icon/ios/icon@2x.png" width="114" />
        <icon height="120" src="res/icon/ios/icon-Small-40@3x.png" width="120" />
        <icon height="180" src="res/icon/ios/icon-60@3x.png" width="180" />
        <icon height="87" src="res/icon/ios/icon-Small@3x.png" width="87" />
        <icon height="167" src="res/icon/ios/icon-83.5@2x.png" width="167" />
        <icon height="1024" src="res/icon/ios/icon-1024.png" width="1024" />
        <splash height="480" src="res/screen/ios/Default~iphone.png" width="320" />
        <splash height="960" src="res/screen/ios/Default@2x~iphone.png" width="640" />
        <splash height="1024" src="res/screen/ios/Default-Portrait~ipad.png" width="768" />
        <splash height="2048" src="res/screen/ios/Default-Portrait@2x~ipad.png" width="1536" />
        <splash height="768" src="res/screen/ios/Default-Landscape~ipad.png" width="1024" />
        <splash height="1536" src="res/screen/ios/Default-Landscape@2x~ipad.png" width="2048" />
        <splash height="1136" src="res/screen/ios/Default-568h@2x~iphone.png" width="640" />
        <splash height="1334" src="res/screen/ios/Default-667h@2x.png" width="750" />
        <splash height="750" src="res/screen/ios/Default-Landscape@2x~iphone6.png" width="1334" />
        <splash height="2208" src="res/screen/ios/Default-Portrait-736h@3x.png" width="1242" />
        <splash height="1242" src="res/screen/ios/Default-Landscape-736h@3x.png" width="2208" />
        <splash height="2732" src="res/screen/ios/Default-iPadPro-Portrait@2x~ipad.png" width="2048" />
        <splash height="2048" src="res/screen/ios/Default-iPadPro-Landscape@2x~ipad.png" width="2732" />
        <splash src="res/screen/ios/Default@2x~iphone~anyany.png" />
        <splash src="res/screen/ios/Default@2x~iphone~comany.png" />
        <splash src="res/screen/ios/Default@2x~iphone~comcom.png" />
        <splash src="res/screen/ios/Default@3x~iphone~anyany.png" />
        <splash src="res/screen/ios/Default@3x~iphone~anycom.png" />
        <splash src="res/screen/ios/Default@3x~iphone~comany.png" />
        <splash src="res/screen/ios/Default@2x~ipad~anyany.png" />
        <splash src="res/screen/ios/Default@2x~ipad~comany.png" />
        <preference name="AllowInlineMediaPlayback" value="false" />
        <preference name="BackupWebStorage" value="cloud" />
        <preference name="DisallowOverscroll" value="false" />
        <preference name="EnableViewportScale" value="false" />
        <preference name="KeyboardDisplayRequiresUserAction" value="true" />
        <preference name="MediaPlaybackRequiresUserAction" value="false" />
        <preference name="SuppressesIncrementalRendering" value="false" />
        <preference name="SuppressesLongPressGesture" value="false" />
        <preference name="Suppresses3DTouchGesture" value="false" />
        <preference name="GapBetweenPages" value="0" />
        <preference name="PageLength" value="0" />
        <preference name="PaginationBreakingMode" value="page" />
        <preference name="PaginationMode" value="unpaginated" />
        <preference name="SAPKapselHandleHttpRequests" value="true" />
        <preference name="openurlscheme.afaria" value="$(PRODUCT_BUNDLE_IDENTIFIER).afaria" />
        <preference name="openurlscheme.xcallbackurl" value="$(PRODUCT_BUNDLE_IDENTIFIER).xcallbackurl" />
        <preference name="homeUrlkey" value="fioriURL" />
        <preference name="CameraUsesGeolocation" value="false" />
        <preference name="StatusBarOverlaysWebView" value="false" />
        <preference name="StatusBarStyle" value="default" />
        <preference name="useBusyIndicator" value="true" />
        <preference name="emailCertificateLabel" value="Client Certificate" />
        <preference name="AutoHideSplashScreen" value="true" />
        <preference name="FadeSplashScreen" value="false" />
        <preference name="helpUrl" value="https://help.sap.com/doc/d55f83e12e4b40779158fbaf08fe0f14/1.9/en-US/index.html" />
        <preference name="trustUserCertificates" value="true" />
        <preference name="cleartextTrafficPermitted" value="true" />
        <preference name="xwalkVersion" value="23+" />
        <preference name="WKWebViewOnly" value="true" />
        <preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine" />
        <preference name="Orientation" value="all" />
        <preference name="deployment-target" value="12.4.1" />
        <preference name="StatusBarBackgroundColor" value="#FFFFFF" />
    </widget>
    

     

    • Hi Hakan,

      As indicated in the blog post, there are changes required in Cordova. Since you’ve downloaded the project, you could update Cordova manually to version 5.1.1. However, I cannot guarantee that our mobile sdk works fine with that version.

      We are planning a new release of the SDK on short term.

      Thanks,
      Ludo

  • Hi Ludo,

    Thanks for your reply.

    Should i update cordova manually on XCode? Is it a setting unique to Custom Fiori Client or Cordova? How can i do this?
    I think then I need to re-create ipa/app/archive file. I couldn’t re-create that again.

    Thank you so much.

    • Hi Hakan,

      I have not verified whether this works, so bare with me …

      Open a terminal and navigate to the project’s root folder. The CLI command “cordova info” should provide you information on the project, including which version of the cordova iOS platform is used.

      To upgrade this platform code, use the following commands:

      cordova platform rm ios
      
      cordova platform add ios@5.1.1 --searchpath $KAPSEL_HOME/plugins

      As you can see, you’ll need to have the Kapsel SDK (part of the mobile SDK) installed locally.

      Once the update is done, you should be able to build the app using “cordova build ios”. After this you can use Xcode for subsequent builds.

      Regards,
      Ludo

       

  • Hi Ludo, thanks for this insghts!

    I changed the config.xml like described in your blog and in OSS 2905323, but nevertheless i get the deprecation message, about wkwebview when submitting the hybrid app to the public appstore.

    “ITMS-90809: Deprecated API Usage – App updates that use UIWebView will no longer be accepted as of December 2020. Instead, use WKWebView for improved security and reliability. Learn more (https://developer.apple.com/documentation/uikit/uiwebview).”

    I use the Cloud Build Service of SAP Cloud Plattform Mobile Service and SAP Web IDE Fullstack.

    I checked the version of the cordova_ios used by SAP in Cloud Build service, it is 5.0.1.

    {
    “Platform”: “iOS”,
    “number”: “3”,
    “type”: “CORDOVA”,
    “kapsel”: “4.3.0-SDK32_SP00_PL00”,
    “node”: “8.12.0”,
    “cordova_cli”: “9.0.0”,
    “cordova_ios”: “5.0.1”,
    “xcode”: “11.2.1”,
    “Id”: “2e7e7cb01dea0e217aaf85b7584bb608”,
    “selectedMinOS”: “12.4.1”,
    “options”: {
    “IsOfflineEnabled”: true,
    “IsDebug”: false,
    “SaveProjectFiles”: true,
    “IsPrivacyScreenDisabled”: true
    }

    Is this the problem? Do you know when SAP will fix the cordova_ios version of the SAP Cloud Build Service?

    Thanks for any information!

    Best regards

    Volker

    • Hi Volker,

      Our engineering team is working on an update of the Cloud Build Service. Unfortunately I cannot provide a target date for this.

      Alternatively, you could build the app locally:

      1. Download the XCode project from our Cloud Build Service
      2. Download and install Kapsel SDK 3.2 SP01 from https://support.sap.com/en/my-support/software-downloads.html
      3. Update the project locally with Cordova for iOS 5.1.1 and the Kapsel plugins from 3.2 SP01
      4. Rebuild locally.

      Regards,
      Ludo