Browse Source

[add] cordova ios

x 5 years ago
parent
commit
b20ba67bd0
100 changed files with 12668 additions and 4 deletions
  1. 33 0
      cordova/config.xml
  2. 145 0
      cordova/package-lock.json
  3. 9 3
      cordova/package.json
  4. 379 1
      cordova/platforms/android/platform_www/cordova_plugins.js
  5. 182 0
      cordova/platforms/android/platform_www/plugins/code-push/script/acquisition-sdk.js
  6. 29 0
      cordova/platforms/android/platform_www/plugins/cordova-plugin-zip/zip.js
  7. 5 0
      cordova/platforms/ios/.gitignore
  8. 25 0
      cordova/platforms/ios/CordovaLib/Classes/Private/CDVDebug.h
  9. 31 0
      cordova/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.h
  10. 99 0
      cordova/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m
  11. 24 0
      cordova/platforms/ios/CordovaLib/Classes/Private/CDVPlugin+Private.h
  12. 26 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h
  13. 70 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m
  14. 27 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h
  15. 86 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m
  16. 36 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h
  17. 151 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m
  18. 27 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.h
  19. 39 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m
  20. 26 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.h
  21. 37 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.m
  22. 29 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.h
  23. 607 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m
  24. 27 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.h
  25. 49 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.m
  26. 32 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.h
  27. 163 0
      cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.m
  28. 30 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDV.h
  29. 28 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVAppDelegate.h
  30. 97 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVAppDelegate.m
  31. 118 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVAvailability.h
  32. 26 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVAvailabilityDeprecated.h
  33. 49 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandDelegate.h
  34. 36 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandDelegateImpl.h
  35. 181 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandDelegateImpl.m
  36. 39 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandQueue.h
  37. 194 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandQueue.m
  38. 30 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVConfigParser.h
  39. 81 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVConfigParser.m
  40. 52 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVInvokedUrlCommand.h
  41. 116 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVInvokedUrlCommand.m
  42. 39 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin+Resources.h
  43. 38 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin+Resources.m
  44. 74 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin.h
  45. 199 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin.m
  46. 83 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVPluginResult.h
  47. 203 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVPluginResult.m
  48. 28 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVScreenOrientationDelegate.h
  49. 27 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVTimer.h
  50. 123 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVTimer.m
  51. 32 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVURLSchemeHandler.h
  52. 108 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVURLSchemeHandler.m
  53. 77 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVViewController.h
  54. 813 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVViewController.m
  55. 41 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVWebViewEngineProtocol.h
  56. 34 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVWhitelist.h
  57. 285 0
      cordova/platforms/ios/CordovaLib/Classes/Public/CDVWhitelist.m
  58. 35 0
      cordova/platforms/ios/CordovaLib/Classes/Public/NSDictionary+CordovaPreferences.h
  59. 92 0
      cordova/platforms/ios/CordovaLib/Classes/Public/NSDictionary+CordovaPreferences.m
  60. 29 0
      cordova/platforms/ios/CordovaLib/Classes/Public/NSMutableArray+QueueAdditions.h
  61. 58 0
      cordova/platforms/ios/CordovaLib/Classes/Public/NSMutableArray+QueueAdditions.m
  62. 791 0
      cordova/platforms/ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
  63. 19 0
      cordova/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/x.xcuserdatad/xcschemes/xcschememanagement.plist
  64. 22 0
      cordova/platforms/ios/CordovaLib/CordovaLib_Prefix.pch
  65. 1 0
      cordova/platforms/ios/CordovaLib/VERSION
  66. 2104 0
      cordova/platforms/ios/CordovaLib/cordova.js
  67. 8 0
      cordova/platforms/ios/Podfile
  68. 16 0
      cordova/platforms/ios/frameworks.json
  69. 203 0
      cordova/platforms/ios/ios.json
  70. 20 0
      cordova/platforms/ios/pods-debug.xcconfig
  71. 20 0
      cordova/platforms/ios/pods-release.xcconfig
  72. 5 0
      cordova/platforms/ios/pods.json
  73. 596 0
      cordova/platforms/ios/美天旺.xcodeproj/project.pbxproj
  74. 7 0
      cordova/platforms/ios/美天旺.xcworkspace/contents.xcworkspacedata
  75. 8 0
      cordova/platforms/ios/美天旺.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  76. 91 0
      cordova/platforms/ios/美天旺.xcworkspace/xcshareddata/xcschemes/美天旺.xcscheme
  77. BIN
      cordova/platforms/ios/美天旺.xcworkspace/xcuserdata/x.xcuserdatad/UserInterfaceState.xcuserstate
  78. 14 0
      cordova/platforms/ios/美天旺.xcworkspace/xcuserdata/x.xcuserdatad/xcschemes/xcschememanagement.plist
  79. 6 0
      cordova/plugins/android.json
  80. 27 0
      cordova/plugins/cordova-plugin-fullscreen/LICENSE
  81. 104 0
      cordova/plugins/cordova-plugin-fullscreen/README.md
  82. 7 0
      cordova/plugins/cordova-plugin-fullscreen/example/README.md
  83. 13 0
      cordova/plugins/cordova-plugin-fullscreen/example/config.xml
  84. 83 0
      cordova/plugins/cordova-plugin-fullscreen/example/hooks/README.md
  85. 64 0
      cordova/plugins/cordova-plugin-fullscreen/package.json
  86. 78 0
      cordova/plugins/cordova-plugin-fullscreen/plugin.xml
  87. 532 0
      cordova/plugins/cordova-plugin-fullscreen/src/android/com/mesmotronic/plugins/FullScreenPlugin.java
  88. 16 0
      cordova/plugins/cordova-plugin-statusbar/.jshintrc
  89. 37 0
      cordova/plugins/cordova-plugin-statusbar/CONTRIBUTING.md
  90. 202 0
      cordova/plugins/cordova-plugin-statusbar/LICENSE
  91. 5 0
      cordova/plugins/cordova-plugin-statusbar/NOTICE
  92. 341 0
      cordova/plugins/cordova-plugin-statusbar/README.md
  93. 191 0
      cordova/plugins/cordova-plugin-statusbar/RELEASENOTES.md
  94. 81 0
      cordova/plugins/cordova-plugin-statusbar/package.json
  95. 99 0
      cordova/plugins/cordova-plugin-statusbar/plugin.xml
  96. 276 0
      cordova/plugins/cordova-plugin-statusbar/src/android/StatusBar.java
  97. 50 0
      cordova/plugins/cordova-plugin-statusbar/src/browser/StatusBarProxy.js
  98. 50 0
      cordova/plugins/cordova-plugin-statusbar/src/ios/CDVStatusBar.h
  99. 479 0
      cordova/plugins/cordova-plugin-statusbar/src/ios/CDVStatusBar.m
  100. 114 0
      cordova/plugins/cordova-plugin-statusbar/src/windows/StatusBarProxy.js

+ 33 - 0
cordova/config.xml

@@ -23,9 +23,42 @@
         <icon src="res/android/mipmap-xhdpi/ic_launcher.png" density="xhdpi" />
         <icon src="res/android/mipmap-xxhdpi/ic_launcher.png" density="xxhdpi" />
         <icon src="res/android/mipmap-xxxhdpi/ic_launcher.png" density="xxxhdpi" />
+        <preference name="CodePushDeploymentKey" value="YOUR-ANDROID-DEPLOYMENT-KEY" />
+        <preference name="CodePushPublicKey" value="YOUR-PUBLIC-KEY" />
     </platform>
+	<preference name="Fullscreen" value="true" />
+	<preference name="WebViewBounce" value="false" />
+	<preference name="DisallowOverscroll" value="true" />
     <platform name="ios">
         <allow-intent href="itms:*" />
         <allow-intent href="itms-apps:*" />
+        <!-- iOS 8.0+ -->
+        <!-- iPhone 6 Plus  -->
+        <icon src="res/ios/icon-60@3x.png" width="180" height="180" />
+        <!-- iOS 7.0+ -->
+        <!-- iPhone / iPod Touch  -->
+        <icon src="res/ios/icon-60.png" width="60" height="60" />
+        <icon src="res/ios/icon-60@2x.png" width="120" height="120" />
+        <!-- iPad -->
+        <icon src="res/ios/icon-76.png" width="76" height="76" />
+        <icon src="res/ios/icon-76@2x.png" width="152" height="152" />
+        <!-- iOS 6.1 -->
+        <!-- Spotlight Icon -->
+        <icon src="res/ios/icon-40.png" width="40" height="40" />
+        <icon src="res/ios/icon-40@2x.png" width="80" height="80" />
+        <!-- iPhone / iPod Touch -->
+        <icon src="res/ios/icon.png" width="57" height="57" />
+        <icon src="res/ios/icon@2x.png" width="114" height="114" />
+        <!-- iPad -->
+        <icon src="res/ios/icon-72.png" width="72" height="72" />
+        <icon src="res/ios/icon-72@2x.png" width="144" height="144" />
+        <!-- iPhone Spotlight and Settings Icon -->
+        <icon src="res/ios/icon-small.png" width="29" height="29" />
+        <icon src="res/ios/icon-small@2x.png" width="58" height="58" />
+        <!-- iPad Spotlight and Settings Icon -->
+        <icon src="res/ios/icon-50.png" width="50" height="50" />
+        <icon src="res/ios/icon-50@2x.png" width="100" height="100" />
+        <preference name="CodePushDeploymentKey" value="YOUR-ANDROID-DEPLOYMENT-KEY" />
+        <preference name="CodePushPublicKey" value="YOUR-PUBLIC-KEY" />
     </platform>
 </widget>

+ 145 - 0
cordova/package-lock.json

@@ -92,6 +92,15 @@
       "integrity": "sha1-j9iL0WMsukocjD49cVnwi7lbS54=",
       "dev": true
     },
+    "bplist-creator": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npm.taobao.org/bplist-creator/download/bplist-creator-0.0.8.tgz",
+      "integrity": "sha1-VrKm556a7D/DO/gx0JNH1zeU55w=",
+      "dev": true,
+      "requires": {
+        "stream-buffers": "~2.2.0"
+      }
+    },
     "bplist-parser": {
       "version": "0.2.0",
       "resolved": "https://registry.npm.taobao.org/bplist-parser/download/bplist-parser-0.2.0.tgz",
@@ -163,6 +172,32 @@
         "underscore": "^1.9.2"
       }
     },
+    "cordova-ios": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npm.taobao.org/cordova-ios/download/cordova-ios-6.1.1.tgz",
+      "integrity": "sha1-M0cwPdvDqYBz/LXg069H22bqJJE=",
+      "dev": true,
+      "requires": {
+        "cordova-common": "^4.0.2",
+        "fs-extra": "^9.0.0",
+        "ios-sim": "^8.0.2",
+        "nopt": "^4.0.3",
+        "plist": "^3.0.1",
+        "semver": "^7.3.2",
+        "unorm": "^1.6.0",
+        "which": "^2.0.2",
+        "xcode": "^3.0.1",
+        "xml-escape": "^1.1.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.3.2",
+          "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.2.tgz?cache=0&sync_timestamp=1586886267748&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.2.tgz",
+          "integrity": "sha1-YElisFK4HtB4aq6EOJ/7pw/9OTg=",
+          "dev": true
+        }
+      }
+    },
     "cordova-plugin-customurlscheme": {
       "version": "5.0.2",
       "resolved": "https://registry.npm.taobao.org/cordova-plugin-customurlscheme/download/cordova-plugin-customurlscheme-5.0.2.tgz",
@@ -175,12 +210,24 @@
       "integrity": "sha1-wrQbfv0EVd0Jf4k1bYW/3V2t6w8=",
       "dev": true
     },
+    "cordova-plugin-fullscreen": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npm.taobao.org/cordova-plugin-fullscreen/download/cordova-plugin-fullscreen-1.3.0.tgz",
+      "integrity": "sha1-JXOduEHSIQbdzSan3igpOFx/M4I=",
+      "dev": true
+    },
     "cordova-plugin-jcore": {
       "version": "1.3.3",
       "resolved": "https://registry.npm.taobao.org/cordova-plugin-jcore/download/cordova-plugin-jcore-1.3.3.tgz",
       "integrity": "sha1-2VcRt6HiAEduQiTaw00ork594B8=",
       "dev": true
     },
+    "cordova-plugin-statusbar": {
+      "version": "2.4.3",
+      "resolved": "https://registry.npm.taobao.org/cordova-plugin-statusbar/download/cordova-plugin-statusbar-2.4.3.tgz",
+      "integrity": "sha1-zFV672bCdITg9/BFAEBA0DMh+C0=",
+      "dev": true
+    },
     "cordova-plugin-wechat": {
       "version": "git+https://github.com/xu-li/cordova-plugin-wechat.git#82f4fbc259ea7371eed2eff57645b29fd76af718",
       "from": "git+https://github.com/xu-li/cordova-plugin-wechat.git#develop",
@@ -380,6 +427,35 @@
       "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=",
       "dev": true
     },
+    "ios-sim": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npm.taobao.org/ios-sim/download/ios-sim-8.0.2.tgz",
+      "integrity": "sha1-4jlKy220N4919MP/hhC79PR5XEM=",
+      "dev": true,
+      "requires": {
+        "bplist-parser": "^0.0.6",
+        "nopt": "1.0.9",
+        "plist": "^3.0.1",
+        "simctl": "^2"
+      },
+      "dependencies": {
+        "bplist-parser": {
+          "version": "0.0.6",
+          "resolved": "https://registry.npm.taobao.org/bplist-parser/download/bplist-parser-0.0.6.tgz",
+          "integrity": "sha1-ONo0cYF9+dRKs4kuJ3B7u9daEbk=",
+          "dev": true
+        },
+        "nopt": {
+          "version": "1.0.9",
+          "resolved": "https://registry.npm.taobao.org/nopt/download/nopt-1.0.9.tgz?cache=0&sync_timestamp=1597649875375&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnopt%2Fdownload%2Fnopt-1.0.9.tgz",
+          "integrity": "sha1-O8DXy6e/sNWmdtvtfA6+SKT9RU4=",
+          "dev": true,
+          "requires": {
+            "abbrev": "1"
+          }
+        }
+      }
+    },
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz",
@@ -669,6 +745,41 @@
       "integrity": "sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw=",
       "dev": true
     },
+    "simctl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npm.taobao.org/simctl/download/simctl-2.0.0.tgz",
+      "integrity": "sha1-4/HGkIc1lp4j4JIrDLEWGEPdDFk=",
+      "dev": true,
+      "requires": {
+        "shelljs": "^0.2.6",
+        "tail": "^0.4.0"
+      },
+      "dependencies": {
+        "shelljs": {
+          "version": "0.2.6",
+          "resolved": "https://registry.npm.taobao.org/shelljs/download/shelljs-0.2.6.tgz?cache=0&sync_timestamp=1587787210621&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fshelljs%2Fdownload%2Fshelljs-0.2.6.tgz",
+          "integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=",
+          "dev": true
+        }
+      }
+    },
+    "simple-plist": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npm.taobao.org/simple-plist/download/simple-plist-1.1.1.tgz?cache=0&sync_timestamp=1601524607289&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsimple-plist%2Fdownload%2Fsimple-plist-1.1.1.tgz",
+      "integrity": "sha1-VDZ8oovFmWqYLDJcHEpMGgX0BHw=",
+      "dev": true,
+      "requires": {
+        "bplist-creator": "0.0.8",
+        "bplist-parser": "0.2.0",
+        "plist": "^3.0.1"
+      }
+    },
+    "stream-buffers": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npm.taobao.org/stream-buffers/download/stream-buffers-2.2.0.tgz",
+      "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=",
+      "dev": true
+    },
     "string.prototype.codepointat": {
       "version": "0.2.1",
       "resolved": "https://registry.npm.taobao.org/string.prototype.codepointat/download/string.prototype.codepointat-0.2.1.tgz",
@@ -687,6 +798,12 @@
       "integrity": "sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0=",
       "dev": true
     },
+    "tail": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npm.taobao.org/tail/download/tail-0.4.0.tgz",
+      "integrity": "sha1-0p3nJ1DMmdseBTr/E8NZ7PtxMAI=",
+      "dev": true
+    },
     "to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz",
@@ -708,6 +825,18 @@
       "integrity": "sha1-thodoXPoQ1sv48Z9Kbmt+FlL0W0=",
       "dev": true
     },
+    "unorm": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npm.taobao.org/unorm/download/unorm-1.6.0.tgz",
+      "integrity": "sha1-ApsolmH7pxTxqa9DnrUdmxbCBa8=",
+      "dev": true
+    },
+    "uuid": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npm.taobao.org/uuid/download/uuid-7.0.3.tgz",
+      "integrity": "sha1-xcnyyM8l3Ao3LE3xRBxB9b0MaAs=",
+      "dev": true
+    },
     "which": {
       "version": "2.0.2",
       "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz",
@@ -734,6 +863,22 @@
       "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
       "dev": true
     },
+    "xcode": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npm.taobao.org/xcode/download/xcode-3.0.1.tgz?cache=0&sync_timestamp=1602463709672&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxcode%2Fdownload%2Fxcode-3.0.1.tgz",
+      "integrity": "sha1-PvtiqsZBqyxwJFj5oDAmlhRqpTw=",
+      "dev": true,
+      "requires": {
+        "simple-plist": "^1.1.0",
+        "uuid": "^7.0.3"
+      }
+    },
+    "xml-escape": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npm.taobao.org/xml-escape/download/xml-escape-1.1.0.tgz",
+      "integrity": "sha1-OQTBQ/qOs6ADDsZG0pAqLxtwbEQ=",
+      "dev": true
+    },
     "xmlbuilder": {
       "version": "9.0.7",
       "resolved": "https://registry.npm.taobao.org/xmlbuilder/download/xmlbuilder-9.0.7.tgz?cache=0&sync_timestamp=1586386503877&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxmlbuilder%2Fdownload%2Fxmlbuilder-9.0.7.tgz",

+ 9 - 3
cordova/package.json

@@ -14,9 +14,12 @@
   "license": "Apache-2.0",
   "devDependencies": {
     "cordova-android": "^9.0.0",
+    "cordova-ios": "^6.1.1",
     "cordova-plugin-customurlscheme": "^5.0.2",
     "cordova-plugin-device": "^2.0.3",
+    "cordova-plugin-fullscreen": "^1.3.0",
     "cordova-plugin-jcore": "^1.3.3",
+    "cordova-plugin-statusbar": "^2.4.3",
     "cordova-plugin-wechat": "git+https://github.com/xu-li/cordova-plugin-wechat.git#develop",
     "cordova-plugin-whitelist": "^1.3.4",
     "jpush-phonegap-plugin": "https://gitee.com/scnon/jpush-phonegap-plugin.git"
@@ -37,11 +40,14 @@
         "ANDROID_SCHEME": "app",
         "ANDROID_HOST": "twong.com",
         "ANDROID_PATHPREFIX": "/open"
-      }
+      },
+      "cordova-plugin-fullscreen": {},
+      "cordova-plugin-statusbar": {}
     },
     "platforms": [
-      "android"
+      "android",
+      "ios"
     ]
   },
   "dependencies": {}
-}
+}

+ 379 - 1
cordova/platforms/android/platform_www/cordova_plugins.js

@@ -31,6 +31,376 @@ cordova.define('cordova/plugin_list', function(require, exports, module) {
       "clobbers": [
         "window.plugins.launchmyapp"
       ]
+    },
+    {
+      "id": "cordova-plugin-fullscreen.AndroidFullScreen",
+      "file": "plugins/cordova-plugin-fullscreen/www/AndroidFullScreen.js",
+      "pluginId": "cordova-plugin-fullscreen",
+      "clobbers": [
+        "AndroidFullScreen"
+      ]
+    },
+    {
+      "id": "cordova-plugin-statusbar.statusbar",
+      "file": "plugins/cordova-plugin-statusbar/www/statusbar.js",
+      "pluginId": "cordova-plugin-statusbar",
+      "clobbers": [
+        "window.StatusBar"
+      ]
+    },
+    {
+      "id": "code-push.AcquisitionManager",
+      "file": "plugins/code-push/script/acquisition-sdk.js",
+      "pluginId": "code-push",
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-dialogs.notification",
+      "file": "plugins/cordova-plugin-dialogs/www/notification.js",
+      "pluginId": "cordova-plugin-dialogs",
+      "merges": [
+        "navigator.notification"
+      ]
+    },
+    {
+      "id": "cordova-plugin-dialogs.notification_android",
+      "file": "plugins/cordova-plugin-dialogs/www/android/notification.js",
+      "pluginId": "cordova-plugin-dialogs",
+      "merges": [
+        "navigator.notification"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryEntry",
+      "file": "plugins/cordova-plugin-file/www/DirectoryEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.DirectoryReader",
+      "file": "plugins/cordova-plugin-file/www/DirectoryReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.DirectoryReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Entry",
+      "file": "plugins/cordova-plugin-file/www/Entry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Entry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.File",
+      "file": "plugins/cordova-plugin-file/www/File.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.File"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileEntry",
+      "file": "plugins/cordova-plugin-file/www/FileEntry.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileEntry"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileError",
+      "file": "plugins/cordova-plugin-file/www/FileError.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileError"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileReader",
+      "file": "plugins/cordova-plugin-file/www/FileReader.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileReader"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileSystem",
+      "file": "plugins/cordova-plugin-file/www/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadOptions",
+      "file": "plugins/cordova-plugin-file/www/FileUploadOptions.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadOptions"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileUploadResult",
+      "file": "plugins/cordova-plugin-file/www/FileUploadResult.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileUploadResult"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.FileWriter",
+      "file": "plugins/cordova-plugin-file/www/FileWriter.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.FileWriter"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Flags",
+      "file": "plugins/cordova-plugin-file/www/Flags.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Flags"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.LocalFileSystem",
+      "file": "plugins/cordova-plugin-file/www/LocalFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.LocalFileSystem"
+      ],
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.Metadata",
+      "file": "plugins/cordova-plugin-file/www/Metadata.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.Metadata"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.ProgressEvent",
+      "file": "plugins/cordova-plugin-file/www/ProgressEvent.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.ProgressEvent"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems",
+      "file": "plugins/cordova-plugin-file/www/fileSystems.js",
+      "pluginId": "cordova-plugin-file"
+    },
+    {
+      "id": "cordova-plugin-file.requestFileSystem",
+      "file": "plugins/cordova-plugin-file/www/requestFileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "clobbers": [
+        "window.requestFileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.resolveLocalFileSystemURI",
+      "file": "plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "window"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.isChrome",
+      "file": "plugins/cordova-plugin-file/www/browser/isChrome.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.androidFileSystem",
+      "file": "plugins/cordova-plugin-file/www/android/FileSystem.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "FileSystem"
+      ]
+    },
+    {
+      "id": "cordova-plugin-file.fileSystems-roots",
+      "file": "plugins/cordova-plugin-file/www/fileSystems-roots.js",
+      "pluginId": "cordova-plugin-file",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-file.fileSystemPaths",
+      "file": "plugins/cordova-plugin-file/www/fileSystemPaths.js",
+      "pluginId": "cordova-plugin-file",
+      "merges": [
+        "cordova"
+      ],
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-advanced-http.cookie-handler",
+      "file": "plugins/cordova-plugin-advanced-http/www/cookie-handler.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.dependency-validator",
+      "file": "plugins/cordova-plugin-advanced-http/www/dependency-validator.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.error-codes",
+      "file": "plugins/cordova-plugin-advanced-http/www/error-codes.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.global-configs",
+      "file": "plugins/cordova-plugin-advanced-http/www/global-configs.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.helpers",
+      "file": "plugins/cordova-plugin-advanced-http/www/helpers.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.js-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/js-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.local-storage-store",
+      "file": "plugins/cordova-plugin-advanced-http/www/local-storage-store.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.lodash",
+      "file": "plugins/cordova-plugin-advanced-http/www/lodash.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.messages",
+      "file": "plugins/cordova-plugin-advanced-http/www/messages.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.ponyfills",
+      "file": "plugins/cordova-plugin-advanced-http/www/ponyfills.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.public-interface",
+      "file": "plugins/cordova-plugin-advanced-http/www/public-interface.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.tough-cookie",
+      "file": "plugins/cordova-plugin-advanced-http/www/umd-tough-cookie.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.url-util",
+      "file": "plugins/cordova-plugin-advanced-http/www/url-util.js",
+      "pluginId": "cordova-plugin-advanced-http"
+    },
+    {
+      "id": "cordova-plugin-advanced-http.http",
+      "file": "plugins/cordova-plugin-advanced-http/www/advanced-http.js",
+      "pluginId": "cordova-plugin-advanced-http",
+      "clobbers": [
+        "cordova.plugin.http"
+      ]
+    },
+    {
+      "id": "cordova-plugin-zip.Zip",
+      "file": "plugins/cordova-plugin-zip/zip.js",
+      "pluginId": "cordova-plugin-zip",
+      "clobbers": [
+        "zip"
+      ]
+    },
+    {
+      "id": "cordova-plugin-code-push.codePush",
+      "file": "plugins/cordova-plugin-code-push/bin/www/codePush.js",
+      "pluginId": "cordova-plugin-code-push",
+      "clobbers": [
+        "codePush"
+      ]
+    },
+    {
+      "id": "cordova-plugin-code-push.localPackage",
+      "file": "plugins/cordova-plugin-code-push/bin/www/localPackage.js",
+      "pluginId": "cordova-plugin-code-push",
+      "clobbers": [
+        "LocalPackage"
+      ]
+    },
+    {
+      "id": "cordova-plugin-code-push.remotePackage",
+      "file": "plugins/cordova-plugin-code-push/bin/www/remotePackage.js",
+      "pluginId": "cordova-plugin-code-push",
+      "clobbers": [
+        "RemotePackage"
+      ]
+    },
+    {
+      "id": "cordova-plugin-code-push.syncStatus",
+      "file": "plugins/cordova-plugin-code-push/bin/www/syncStatus.js",
+      "pluginId": "cordova-plugin-code-push",
+      "clobbers": [
+        "SyncStatus"
+      ]
+    },
+    {
+      "id": "cordova-plugin-code-push.installMode",
+      "file": "plugins/cordova-plugin-code-push/bin/www/installMode.js",
+      "pluginId": "cordova-plugin-code-push",
+      "clobbers": [
+        "InstallMode"
+      ]
+    },
+    {
+      "id": "cordova-plugin-code-push.codePushUtil",
+      "file": "plugins/cordova-plugin-code-push/bin/www/codePushUtil.js",
+      "pluginId": "cordova-plugin-code-push",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-code-push.fileUtil",
+      "file": "plugins/cordova-plugin-code-push/bin/www/fileUtil.js",
+      "pluginId": "cordova-plugin-code-push",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-code-push.httpRequester",
+      "file": "plugins/cordova-plugin-code-push/bin/www/httpRequester.js",
+      "pluginId": "cordova-plugin-code-push",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-code-push.nativeAppInfo",
+      "file": "plugins/cordova-plugin-code-push/bin/www/nativeAppInfo.js",
+      "pluginId": "cordova-plugin-code-push",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-code-push.package",
+      "file": "plugins/cordova-plugin-code-push/bin/www/package.js",
+      "pluginId": "cordova-plugin-code-push",
+      "runs": true
+    },
+    {
+      "id": "cordova-plugin-code-push.sdk",
+      "file": "plugins/cordova-plugin-code-push/bin/www/sdk.js",
+      "pluginId": "cordova-plugin-code-push",
+      "runs": true
     }
   ];
   module.exports.metadata = {
@@ -39,6 +409,14 @@ cordova.define('cordova/plugin_list', function(require, exports, module) {
     "cordova-plugin-jcore": "1.3.3",
     "jpush-phonegap-plugin": "3.7.6",
     "cordova-plugin-wechat": "3.0.0",
-    "cordova-plugin-customurlscheme": "5.0.2"
+    "cordova-plugin-customurlscheme": "5.0.2",
+    "cordova-plugin-fullscreen": "1.3.0",
+    "cordova-plugin-statusbar": "2.4.3",
+    "code-push": "3.0.1",
+    "cordova-plugin-dialogs": "2.0.2",
+    "cordova-plugin-file": "6.0.2",
+    "cordova-plugin-advanced-http": "3.0.1",
+    "cordova-plugin-zip": "3.1.0",
+    "cordova-plugin-code-push": "1.13.1"
   };
 });

+ 182 - 0
cordova/platforms/android/platform_www/plugins/code-push/script/acquisition-sdk.js

@@ -0,0 +1,182 @@
+cordova.define("code-push.AcquisitionManager", function(require, exports, module) {
+/// <reference path="../definitions/harness.d.ts" />
+var AcquisitionStatus = (function () {
+    function AcquisitionStatus() {
+    }
+    AcquisitionStatus.DeploymentSucceeded = "DeploymentSucceeded";
+    AcquisitionStatus.DeploymentFailed = "DeploymentFailed";
+    return AcquisitionStatus;
+})();
+exports.AcquisitionStatus = AcquisitionStatus;
+var AcquisitionManager = (function () {
+    function AcquisitionManager(httpRequester, configuration) {
+        this._publicPrefixUrl = "v0.1/public/codepush/";
+        this._httpRequester = httpRequester;
+        this._serverUrl = configuration.serverUrl;
+        if (this._serverUrl.slice(-1) !== "/") {
+            this._serverUrl += "/";
+        }
+        this._appVersion = configuration.appVersion;
+        this._clientUniqueId = configuration.clientUniqueId;
+        this._deploymentKey = configuration.deploymentKey;
+        this._ignoreAppVersion = configuration.ignoreAppVersion;
+    }
+    AcquisitionManager.prototype.queryUpdateWithCurrentPackage = function (currentPackage, callback) {
+        var _this = this;
+        if (!currentPackage || !currentPackage.appVersion) {
+            throw new Error("Calling common acquisition SDK with incorrect package"); // Unexpected; indicates error in our implementation
+        }
+        var updateRequest = {
+            deployment_key: this._deploymentKey,
+            app_version: currentPackage.appVersion,
+            package_hash: currentPackage.packageHash,
+            is_companion: this._ignoreAppVersion,
+            label: currentPackage.label,
+            client_unique_id: this._clientUniqueId
+        };
+        var requestUrl = this._serverUrl + this._publicPrefixUrl + "update_check?" + queryStringify(updateRequest);
+        this._httpRequester.request(0 /* GET */, requestUrl, function (error, response) {
+            if (error) {
+                callback(error, null);
+                return;
+            }
+            if (response.statusCode !== 200) {
+                var errorMessage;
+                if (response.statusCode === 0) {
+                    errorMessage = "Couldn't send request to " + requestUrl + ", xhr.statusCode = 0 was returned. One of the possible reasons for that might be connection problems. Please, check your internet connection.";
+                }
+                else {
+                    errorMessage = response.statusCode + ": " + response.body;
+                }
+                callback(new Error(errorMessage), null);
+                return;
+            }
+            try {
+                var responseObject = JSON.parse(response.body);
+                var updateInfo = responseObject.update_info;
+            }
+            catch (error) {
+                callback(error, null);
+                return;
+            }
+            if (!updateInfo) {
+                callback(error, null);
+                return;
+            }
+            else if (updateInfo.update_app_version) {
+                callback(null, { updateAppVersion: true, appVersion: updateInfo.target_binary_range });
+                return;
+            }
+            else if (!updateInfo.is_available) {
+                callback(null, null);
+                return;
+            }
+            var remotePackage = {
+                deploymentKey: _this._deploymentKey,
+                description: updateInfo.description,
+                label: updateInfo.label,
+                appVersion: updateInfo.target_binary_range,
+                isMandatory: updateInfo.is_mandatory,
+                packageHash: updateInfo.package_hash,
+                packageSize: updateInfo.package_size,
+                downloadUrl: updateInfo.download_url
+            };
+            callback(null, remotePackage);
+        });
+    };
+    AcquisitionManager.prototype.reportStatusDeploy = function (deployedPackage, status, previousLabelOrAppVersion, previousDeploymentKey, callback) {
+        var url = this._serverUrl + this._publicPrefixUrl + "report_status/deploy";
+        var body = {
+            app_version: this._appVersion,
+            deployment_key: this._deploymentKey
+        };
+        if (this._clientUniqueId) {
+            body.client_unique_id = this._clientUniqueId;
+        }
+        if (deployedPackage) {
+            body.label = deployedPackage.label;
+            body.app_version = deployedPackage.appVersion;
+            switch (status) {
+                case AcquisitionStatus.DeploymentSucceeded:
+                case AcquisitionStatus.DeploymentFailed:
+                    body.status = status;
+                    break;
+                default:
+                    if (callback) {
+                        if (!status) {
+                            callback(new Error("Missing status argument."), null);
+                        }
+                        else {
+                            callback(new Error("Unrecognized status \"" + status + "\"."), null);
+                        }
+                    }
+                    return;
+            }
+        }
+        if (previousLabelOrAppVersion) {
+            body.previous_label_or_app_version = previousLabelOrAppVersion;
+        }
+        if (previousDeploymentKey) {
+            body.previous_deployment_key = previousDeploymentKey;
+        }
+        callback = typeof arguments[arguments.length - 1] === "function" && arguments[arguments.length - 1];
+        this._httpRequester.request(2 /* POST */, url, JSON.stringify(body), function (error, response) {
+            if (callback) {
+                if (error) {
+                    callback(error, null);
+                    return;
+                }
+                if (response.statusCode !== 200) {
+                    callback(new Error(response.statusCode + ": " + response.body), null);
+                    return;
+                }
+                callback(null, null);
+            }
+        });
+    };
+    AcquisitionManager.prototype.reportStatusDownload = function (downloadedPackage, callback) {
+        var url = this._serverUrl + this._publicPrefixUrl + "report_status/download";
+        var body = {
+            client_unique_id: this._clientUniqueId,
+            deployment_key: this._deploymentKey,
+            label: downloadedPackage.label
+        };
+        this._httpRequester.request(2 /* POST */, url, JSON.stringify(body), function (error, response) {
+            if (callback) {
+                if (error) {
+                    callback(error, null);
+                    return;
+                }
+                if (response.statusCode !== 200) {
+                    callback(new Error(response.statusCode + ": " + response.body), null);
+                    return;
+                }
+                callback(null, null);
+            }
+        });
+    };
+    return AcquisitionManager;
+})();
+exports.AcquisitionManager = AcquisitionManager;
+function queryStringify(object) {
+    var queryString = "";
+    var isFirst = true;
+    for (var property in object) {
+        if (object.hasOwnProperty(property)) {
+            var value = object[property];
+            if (value !== null && typeof value !== "undefined") {
+                if (!isFirst) {
+                    queryString += "&";
+                }
+                queryString += encodeURIComponent(property) + "=";
+                queryString += encodeURIComponent(value);
+            }
+            isFirst = false;
+        }
+    }
+    return queryString;
+}
+
+//# sourceMappingURL=acquisition-sdk.js.map
+
+});

+ 29 - 0
cordova/platforms/android/platform_www/plugins/cordova-plugin-zip/zip.js

@@ -0,0 +1,29 @@
+cordova.define("cordova-plugin-zip.Zip", function(require, exports, module) {
+var exec = cordova.require('cordova/exec');
+
+function newProgressEvent(result) {
+    var event = {
+            loaded: result.loaded,
+            total: result.total
+    };
+    return event;
+}
+
+exports.unzip = function(fileName, outputDirectory, callback, progressCallback) {
+    var win = function(result) {
+        if (result && typeof result.loaded != "undefined") {
+            if (progressCallback) {
+                return progressCallback(newProgressEvent(result));
+            }
+        } else if (callback) {
+            callback(0);
+        }
+    };
+    var fail = function(result) {
+        if (callback) {
+            callback(-1);
+        }
+    };
+    exec(win, fail, 'Zip', 'unzip', [fileName, outputDirectory]);
+};
+});

+ 5 - 0
cordova/platforms/ios/.gitignore

@@ -0,0 +1,5 @@
+*.mode1v3
+*.perspectivev3
+*.pbxuser
+.DS_Store
+build/

+ 25 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/CDVDebug.h

@@ -0,0 +1,25 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#ifdef DEBUG
+    #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
+#else
+    #define DLog(...)
+#endif
+#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)

+ 31 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.h

@@ -0,0 +1,31 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface NSArray (CDVJSONSerializingPrivate)
+- (NSString*)cdv_JSONString;
+@end
+
+@interface NSDictionary (CDVJSONSerializingPrivate)
+- (NSString*)cdv_JSONString;
+@end
+
+@interface NSString (CDVJSONSerializingPrivate)
+- (id)cdv_JSONObject;
+- (id)cdv_JSONFragment;
+@end

+ 99 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/CDVJSON_private.m

@@ -0,0 +1,99 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVJSON_private.h"
+#import <Foundation/NSJSONSerialization.h>
+
+@implementation NSArray (CDVJSONSerializingPrivate)
+
+- (NSString*)cdv_JSONString
+{
+    @autoreleasepool {
+        NSError* error = nil;
+        NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+                                                           options:0
+                                                             error:&error];
+
+        if (error != nil) {
+            NSLog(@"NSArray JSONString error: %@", [error localizedDescription]);
+            return nil;
+        } else {
+            return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+        }
+    }
+}
+
+@end
+
+@implementation NSDictionary (CDVJSONSerializingPrivate)
+
+- (NSString*)cdv_JSONString
+{
+    @autoreleasepool {
+        NSError* error = nil;
+        NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
+                                                           options:NSJSONWritingPrettyPrinted
+                                                             error:&error];
+
+        if (error != nil) {
+            NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]);
+            return nil;
+        } else {
+            return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+        }
+    }
+}
+
+@end
+
+@implementation NSString (CDVJSONSerializingPrivate)
+
+- (id)cdv_JSONObject
+{
+    @autoreleasepool {   
+        NSError* error = nil;
+        id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
+                                                    options:NSJSONReadingMutableContainers
+                                                      error:&error];
+
+        if (error != nil) {
+            NSLog(@"NSString JSONObject error: %@, Malformed Data: %@", [error localizedDescription], self);
+        }
+
+        return object;
+    }
+}
+
+- (id)cdv_JSONFragment
+{
+    @autoreleasepool {
+        NSError* error = nil;
+        id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
+                                                    options:NSJSONReadingAllowFragments
+                                                      error:&error];
+
+        if (error != nil) {
+            NSLog(@"NSString JSONObject error: %@", [error localizedDescription]);
+        }
+
+        return object;
+    }
+}
+
+@end

+ 24 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/CDVPlugin+Private.h

@@ -0,0 +1,24 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface CDVPlugin (Private)
+
+- (instancetype)initWithWebViewEngine:(id <CDVWebViewEngineProtocol>)theWebViewEngine;
+
+@end

+ 26 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h

@@ -0,0 +1,26 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Cordova/CDVPlugin.h>
+
+@interface CDVGestureHandler : CDVPlugin
+
+@property (nonatomic, strong) UILongPressGestureRecognizer* lpgr;
+
+@end

+ 70 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m

@@ -0,0 +1,70 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVGestureHandler.h"
+
+@implementation CDVGestureHandler
+
+- (void)pluginInitialize
+{
+    [self applyLongPressFix];
+}
+
+- (void)applyLongPressFix
+{
+    // You can't suppress 3D Touch and still have regular longpress,
+    // so if this is false, let's not consider the 3D Touch setting at all.
+    if (![self.commandDelegate.settings objectForKey:@"suppresseslongpressgesture"] ||
+        ![[self.commandDelegate.settings objectForKey:@"suppresseslongpressgesture"] boolValue]) {
+        return;
+    }
+
+    self.lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGestures:)];
+    self.lpgr.minimumPressDuration = 0.45f;
+    self.lpgr.allowableMovement = 200.0f;
+
+    // 0.45 is ok for 'regular longpress', 0.05-0.08 is required for '3D Touch longpress',
+    // but since this will also kill onclick handlers (not ontouchend) it's optional.
+    if ([self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] &&
+        [[self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] boolValue]) {
+        self.lpgr.minimumPressDuration = 0.15f;
+    }
+
+    NSArray *views = self.webView.subviews;
+    if (views.count == 0) {
+        NSLog(@"No webview subviews found, not applying the longpress fix.");
+        return;
+    }
+    for (int i=0; i<views.count; i++) {
+        UIView *webViewScrollView = views[i];
+        if ([webViewScrollView isKindOfClass:[UIScrollView class]]) {
+            NSArray *webViewScrollViewSubViews = webViewScrollView.subviews;
+            UIView *browser = webViewScrollViewSubViews[0];
+            [browser addGestureRecognizer:self.lpgr];
+            break;
+        }
+    }
+}
+
+- (void)handleLongPressGestures:(UILongPressGestureRecognizer*)sender
+{
+    
+}
+
+@end

+ 27 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.h

@@ -0,0 +1,27 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Cordova/CDVPlugin.h>
+
+@interface CDVHandleOpenURL : CDVPlugin
+
+@property (nonatomic, strong) NSURL* url;
+@property (nonatomic, assign) BOOL pageLoaded;
+
+@end

+ 86 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVHandleOpenURL/CDVHandleOpenURL.m

@@ -0,0 +1,86 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVHandleOpenURL.h"
+#import <Cordova/CDV.h>
+
+@implementation CDVHandleOpenURL
+
+- (void)pluginInitialize
+{
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationLaunchedWithUrl:) name:CDVPluginHandleOpenURLNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationPageDidLoad:) name:CDVPageDidLoadNotification object:nil];
+}
+
+- (void)applicationLaunchedWithUrl:(NSNotification*)notification
+{
+    NSURL* url = [notification object];
+
+    self.url = url;
+
+    // warm-start handler
+    if (self.pageLoaded) {
+        [self processOpenUrl:self.url pageLoaded:YES];
+        self.url = nil;
+    }
+}
+
+- (void)applicationPageDidLoad:(NSNotification*)notification
+{
+    // cold-start handler
+
+    self.pageLoaded = YES;
+
+    if (self.url) {
+        [self processOpenUrl:self.url pageLoaded:YES];
+        self.url = nil;
+    }
+}
+
+- (void)processOpenUrl:(NSURL*)url pageLoaded:(BOOL)pageLoaded
+{
+    __weak __typeof(self) weakSelf = self;
+
+    dispatch_block_t handleOpenUrl = ^(void) {
+        // calls into javascript global function 'handleOpenURL'
+        NSString* jsString = [NSString stringWithFormat:@"document.addEventListener('deviceready',function(){if (typeof handleOpenURL === 'function') { handleOpenURL(\"%@\");}});", url.absoluteString];
+
+        [weakSelf.webViewEngine evaluateJavaScript:jsString completionHandler:nil];
+    };
+
+    if (!pageLoaded) {
+        NSString* jsString = @"document.readystate";
+        [self.webViewEngine evaluateJavaScript:jsString
+                             completionHandler:^(id object, NSError* error) {
+            if ((error == nil) && [object isKindOfClass:[NSString class]]) {
+                NSString* readyState = (NSString*)object;
+                BOOL ready = [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
+                if (ready) {
+                    handleOpenUrl();
+                } else {
+                    self.url = url;
+                }
+            }
+        }];
+    } else {
+        handleOpenUrl();
+    }
+}
+
+@end

+ 36 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h

@@ -0,0 +1,36 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Cordova/CDVPlugin.h>
+#import <Cordova/CDVWhitelist.h>
+
+#define CDVWebViewNavigationType int
+
+typedef NS_ENUM(NSInteger, CDVIntentAndNavigationFilterValue) {
+    CDVIntentAndNavigationFilterValueIntentAllowed,
+    CDVIntentAndNavigationFilterValueNavigationAllowed,
+    CDVIntentAndNavigationFilterValueNoneAllowed
+};
+
+@interface CDVIntentAndNavigationFilter : CDVPlugin <NSXMLParserDelegate>
+
++ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist;
++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue;
++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType;
+@end

+ 151 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m

@@ -0,0 +1,151 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVIntentAndNavigationFilter.h"
+#import <Cordova/CDV.h>
+
+@interface CDVIntentAndNavigationFilter ()
+
+@property (nonatomic, readwrite) NSMutableArray* allowIntents;
+@property (nonatomic, readwrite) NSMutableArray* allowNavigations;
+@property (nonatomic, readwrite) CDVWhitelist* allowIntentsWhitelist;
+@property (nonatomic, readwrite) CDVWhitelist* allowNavigationsWhitelist;
+
+@end
+
+@implementation CDVIntentAndNavigationFilter
+
+#pragma mark NSXMLParserDelegate
+
+- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict
+{
+    if ([elementName isEqualToString:@"allow-navigation"]) {
+        [self.allowNavigations addObject:attributeDict[@"href"]];
+    }
+    if ([elementName isEqualToString:@"allow-intent"]) {
+        [self.allowIntents addObject:attributeDict[@"href"]];
+    }
+}
+
+- (void)parserDidStartDocument:(NSXMLParser*)parser
+{
+    // file: url <allow-navigations> are added by default
+    // navigation to the scheme used by the app is also allowed
+    self.allowNavigations = [[NSMutableArray alloc] initWithArray:@[ @"file://"]];
+
+    // If the custom app scheme is defined, append it to the allow navigation as default
+    NSString* scheme = ((CDVViewController*)self.viewController).appScheme;
+    if (scheme) {
+        [self.allowNavigations addObject: [NSString stringWithFormat:@"%@://", scheme]];
+    }
+
+    // no intents are added by default
+    self.allowIntents = [[NSMutableArray alloc] init];
+}
+
+- (void)parserDidEndDocument:(NSXMLParser*)parser
+{
+    self.allowIntentsWhitelist = [[CDVWhitelist alloc] initWithArray:self.allowIntents];
+    self.allowNavigationsWhitelist = [[CDVWhitelist alloc] initWithArray:self.allowNavigations];
+}
+
+- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError
+{
+    NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]);
+}
+
+#pragma mark CDVPlugin
+
+- (void)pluginInitialize
+{
+    if ([self.viewController isKindOfClass:[CDVViewController class]]) {
+        [(CDVViewController*)self.viewController parseSettingsWithParser:self];
+    }
+}
+
++ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist
+{
+    // a URL can only allow-intent OR allow-navigation, if both are specified,
+    // only allow-navigation is allowed
+
+    BOOL allowNavigationsPass = [navigationsWhitelist URLIsAllowed:url logFailure:NO];
+    BOOL allowIntentPass = [intentsWhitelist URLIsAllowed:url logFailure:NO];
+
+    if (allowNavigationsPass && allowIntentPass) {
+        return CDVIntentAndNavigationFilterValueNavigationAllowed;
+    } else if (allowNavigationsPass) {
+        return CDVIntentAndNavigationFilterValueNavigationAllowed;
+    } else if (allowIntentPass) {
+        return CDVIntentAndNavigationFilterValueIntentAllowed;
+    }
+
+    return CDVIntentAndNavigationFilterValueNoneAllowed;
+}
+
+- (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url
+{
+    return [[self class] filterUrl:url intentsWhitelist:self.allowIntentsWhitelist navigationsWhitelist:self.allowNavigationsWhitelist];
+}
+
+#define CDVWebViewNavigationTypeLinkClicked 0
+#define CDVWebViewNavigationTypeLinkOther -1
+
++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType
+{
+    return (
+        navigationType == CDVWebViewNavigationTypeLinkClicked ||
+        navigationType == CDVWebViewNavigationTypeLinkOther
+    );
+}
+
++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue
+{
+    NSString* allowIntents_whitelistRejectionFormatString = @"ERROR External navigation rejected - <allow-intent> not set for url='%@'";
+    NSString* allowNavigations_whitelistRejectionFormatString = @"ERROR Internal navigation rejected - <allow-navigation> not set for url='%@'";
+
+    NSURL* url = [request URL];
+
+    switch (filterValue) {
+        case CDVIntentAndNavigationFilterValueNavigationAllowed:
+            return YES;
+        case CDVIntentAndNavigationFilterValueIntentAllowed:
+            // only allow-intent if it's a CDVWebViewNavigationTypeLinkClicked (anchor tag) or CDVWebViewNavigationTypeOther and it's an internal link
+            if ([[self class] shouldOpenURLRequest:request navigationType:navigationType]){
+                [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
+            }
+
+            // consume the request (i.e. no error) if it wasn't handled above
+            return NO;
+        case CDVIntentAndNavigationFilterValueNoneAllowed:
+            // allow-navigation attempt failed for sure
+            NSLog(@"%@", [NSString stringWithFormat:allowNavigations_whitelistRejectionFormatString, [url absoluteString]]);
+            // anchor tag link means it was an allow-intent attempt that failed as well
+            if (CDVWebViewNavigationTypeLinkClicked == navigationType) {
+                NSLog(@"%@", [NSString stringWithFormat:allowIntents_whitelistRejectionFormatString, [url absoluteString]]);
+            }
+            return NO;
+    }
+}
+
+- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType
+{
+    return [[self class] shouldOverrideLoadWithRequest:request navigationType:navigationType filterValue:[self filterUrl:request.URL]];
+}
+
+@end

+ 27 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.h

@@ -0,0 +1,27 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Cordova/CDVPlugin.h>
+
+@interface CDVLaunchScreen : CDVPlugin
+
+- (void)show:(CDVInvokedUrlCommand*)command;
+- (void)hide:(CDVInvokedUrlCommand*)command;
+
+@end

+ 39 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLaunchScreen/CDVLaunchScreen.m

@@ -0,0 +1,39 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVLaunchScreen.h"
+#import <Cordova/CDVViewController.h>
+
+@implementation CDVLaunchScreen
+
+- (void)show:(CDVInvokedUrlCommand*)command
+{
+    if ([self.viewController isKindOfClass:[CDVViewController class]]) {
+        [(CDVViewController*)self.viewController showLaunchScreen:YES];
+    }
+}
+
+- (void)hide:(CDVInvokedUrlCommand*)command
+{
+    if ([self.viewController isKindOfClass:[CDVViewController class]]) {
+        [(CDVViewController*)self.viewController showLaunchScreen:NO];
+    }
+}
+
+@end

+ 26 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.h

@@ -0,0 +1,26 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Cordova/CDVPlugin.h>
+
+@interface CDVLogger : CDVPlugin
+
+- (void)logLevel:(CDVInvokedUrlCommand*)command;
+
+@end

+ 37 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVLogger/CDVLogger.m

@@ -0,0 +1,37 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVLogger.h"
+
+@implementation CDVLogger
+
+/* log a message */
+- (void)logLevel:(CDVInvokedUrlCommand*)command
+{
+    id level = [command argumentAtIndex:0];
+    id message = [command argumentAtIndex:1];
+
+    if ([level isEqualToString:@"LOG"]) {
+        NSLog(@"%@", message);
+    } else {
+        NSLog(@"%@: %@", level, message);
+    }
+}
+
+@end

+ 29 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.h

@@ -0,0 +1,29 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <WebKit/WebKit.h>
+#import <Cordova/CDV.h>
+
+@interface CDVWebViewEngine : CDVPlugin <CDVWebViewEngineProtocol, WKScriptMessageHandler, WKNavigationDelegate>
+
+@property (nonatomic, strong, readonly) id <WKUIDelegate> uiDelegate;
+
+- (void)allowsBackForwardNavigationGestures:(CDVInvokedUrlCommand*)command;
+
+@end

+ 607 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m

@@ -0,0 +1,607 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVWebViewEngine.h"
+#import "CDVWebViewUIDelegate.h"
+#import "CDVWebViewProcessPoolFactory.h"
+#import <Cordova/NSDictionary+CordovaPreferences.h>
+#import "CDVURLSchemeHandler.h"
+
+#import <objc/message.h>
+
+#define CDV_BRIDGE_NAME @"cordova"
+#define CDV_WKWEBVIEW_FILE_URL_LOAD_SELECTOR @"loadFileURL:allowingReadAccessToURL:"
+
+@interface CDVWebViewWeakScriptMessageHandler : NSObject <WKScriptMessageHandler>
+
+@property (nonatomic, weak, readonly) id<WKScriptMessageHandler>scriptMessageHandler;
+
+- (instancetype)initWithScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler;
+
+@end
+
+
+@interface CDVWebViewEngine ()
+
+@property (nonatomic, strong, readwrite) UIView* engineWebView;
+@property (nonatomic, strong, readwrite) id <WKUIDelegate> uiDelegate;
+@property (nonatomic, weak) id <WKScriptMessageHandler> weakScriptMessageHandler;
+@property (nonatomic, strong) CDVURLSchemeHandler * schemeHandler;
+@property (nonatomic, readwrite) NSString *CDV_ASSETS_URL;
+@property (nonatomic, readwrite) Boolean cdvIsFileScheme;
+
+@end
+
+// see forwardingTargetForSelector: selector comment for the reason for this pragma
+#pragma clang diagnostic ignored "-Wprotocol"
+
+@implementation CDVWebViewEngine
+
+@synthesize engineWebView = _engineWebView;
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    self = [super init];
+    if (self) {
+        if (NSClassFromString(@"WKWebView") == nil) {
+            return nil;
+        }
+
+        self.engineWebView = [[WKWebView alloc] initWithFrame:frame];
+    }
+
+    return self;
+}
+
+- (WKWebViewConfiguration*) createConfigurationFromSettings:(NSDictionary*)settings
+{
+    WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init];
+    configuration.processPool = [[CDVWebViewProcessPoolFactory sharedFactory] sharedProcessPool];
+    if (settings == nil) {
+        return configuration;
+    }
+
+    configuration.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO];
+
+    // Set the media types that are required for user action for playback
+    WKAudiovisualMediaTypes mediaType = WKAudiovisualMediaTypeAll; // default
+
+    // targetMediaType will always exist, either from user's "config.xml" or default ("defaults.xml").
+    id targetMediaType = [settings cordovaSettingForKey:@"MediaTypesRequiringUserActionForPlayback"];
+    if ([targetMediaType isEqualToString:@"none"]) {
+        mediaType = WKAudiovisualMediaTypeNone;
+    } else if ([targetMediaType isEqualToString:@"audio"]) {
+        mediaType = WKAudiovisualMediaTypeAudio;
+    } else if ([targetMediaType isEqualToString:@"video"]) {
+        mediaType = WKAudiovisualMediaTypeVideo;
+    } else if ([targetMediaType isEqualToString:@"all"]) {
+        mediaType = WKAudiovisualMediaTypeAll;
+    } else {
+        NSLog(@"Invalid \"MediaTypesRequiringUserActionForPlayback\" was detected. Fallback to default value of \"all\" types.");
+    }
+    configuration.mediaTypesRequiringUserActionForPlayback = mediaType;
+
+    configuration.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO];
+
+    /*
+     * If the old preference key "MediaPlaybackAllowsAirPlay" exists, use it or default to "YES".
+     * Check if the new preference key "AllowsAirPlayForMediaPlayback" exists and overwrite the "MediaPlaybackAllowsAirPlay" value.
+     */
+    BOOL allowsAirPlayForMediaPlayback = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES];
+    if([settings cordovaSettingForKey:@"AllowsAirPlayForMediaPlayback"] != nil) {
+        allowsAirPlayForMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowsAirPlayForMediaPlayback" defaultValue:YES];
+    }
+    configuration.allowsAirPlayForMediaPlayback = allowsAirPlayForMediaPlayback;
+
+    /*
+     * Sets Custom User Agents
+     * - (Default) "userAgent" is set the the clean user agent.
+     *   E.g.
+     *     UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
+     *
+     * - If "OverrideUserAgent" is set, it will overwrite the entire "userAgent" value. The "AppendUserAgent" will be iggnored if set.
+     *   Notice: The override logic is handled in the "pluginInitialize" method.
+     *   E.g.
+     *     OverrideUserAgent = "foobar"
+     *     UserAgent = "foobar"
+     *
+     * - If "AppendUserAgent" is set and "OverrideUserAgent" is not set, the user defined "AppendUserAgent" will be appended to the "userAgent"
+     *   E.g.
+     *     AppendUserAgent = "foobar"
+     *     UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 foobar"
+     */
+    NSString *userAgent = configuration.applicationNameForUserAgent;
+    if (
+        [settings cordovaSettingForKey:@"OverrideUserAgent"] == nil &&
+        [settings cordovaSettingForKey:@"AppendUserAgent"] != nil
+        ) {
+        userAgent = [NSString stringWithFormat:@"%@ %@", userAgent, [settings cordovaSettingForKey:@"AppendUserAgent"]];
+    }
+    configuration.applicationNameForUserAgent = userAgent;
+
+    if (@available(iOS 13.0, *)) {
+        NSString *contentMode = [settings cordovaSettingForKey:@"PreferredContentMode"];
+        if ([contentMode isEqual: @"mobile"]) {
+            configuration.defaultWebpagePreferences.preferredContentMode = WKContentModeMobile;
+        } else if ([contentMode isEqual: @"desktop"]) {
+            configuration.defaultWebpagePreferences.preferredContentMode = WKContentModeDesktop;
+        }
+        
+    }
+
+    return configuration;
+}
+
+- (void)pluginInitialize
+{
+    // viewController would be available now. we attempt to set all possible delegates to it, by default
+    CDVViewController* vc = (CDVViewController*)self.viewController;
+    NSDictionary* settings = self.commandDelegate.settings;
+
+    NSString *scheme = [settings cordovaSettingForKey:@"scheme"];
+
+    // If scheme is file or nil, then default to file scheme
+    self.cdvIsFileScheme = [scheme isEqualToString: @"file"] || scheme == nil;
+
+    NSString *hostname = @"";
+    if(!self.cdvIsFileScheme) {
+        if(scheme == nil || [WKWebView handlesURLScheme:scheme]){
+            scheme = @"app";
+        }
+        vc.appScheme = scheme;
+
+        hostname = [settings cordovaSettingForKey:@"hostname"];
+        if(hostname == nil){
+            hostname = @"localhost";
+        }
+
+        self.CDV_ASSETS_URL = [NSString stringWithFormat:@"%@://%@", scheme, hostname];
+    }
+
+    CDVWebViewUIDelegate* uiDelegate = [[CDVWebViewUIDelegate alloc] initWithTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]];
+    uiDelegate.allowNewWindows = [settings cordovaBoolSettingForKey:@"AllowNewWindows" defaultValue:NO];
+    self.uiDelegate = uiDelegate;
+
+    CDVWebViewWeakScriptMessageHandler *weakScriptMessageHandler = [[CDVWebViewWeakScriptMessageHandler alloc] initWithScriptMessageHandler:self];
+
+    WKUserContentController* userContentController = [[WKUserContentController alloc] init];
+    [userContentController addScriptMessageHandler:weakScriptMessageHandler name:CDV_BRIDGE_NAME];
+
+    if(self.CDV_ASSETS_URL) {
+        NSString *scriptCode = [NSString stringWithFormat:@"window.CDV_ASSETS_URL = '%@';", self.CDV_ASSETS_URL];
+        WKUserScript *wkScript = [[WKUserScript alloc] initWithSource:scriptCode injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
+
+        if (wkScript) {
+            [userContentController addUserScript:wkScript];
+        }
+    }
+
+    WKWebViewConfiguration* configuration = [self createConfigurationFromSettings:settings];
+    configuration.userContentController = userContentController;
+
+    // Do not configure the scheme handler if the scheme is default (file)
+    if(!self.cdvIsFileScheme) {
+        self.schemeHandler = [[CDVURLSchemeHandler alloc] initWithVC:vc];
+        [configuration setURLSchemeHandler:self.schemeHandler forURLScheme:scheme];
+    }
+
+    // re-create WKWebView, since we need to update configuration
+    WKWebView* wkWebView = [[WKWebView alloc] initWithFrame:self.engineWebView.frame configuration:configuration];
+    wkWebView.UIDelegate = self.uiDelegate;
+
+    /*
+     * This is where the "OverrideUserAgent" is handled. This will replace the entire UserAgent
+     * with the user defined custom UserAgent.
+     */
+    if ([settings cordovaSettingForKey:@"OverrideUserAgent"] != nil) {
+        wkWebView.customUserAgent = [settings cordovaSettingForKey:@"OverrideUserAgent"];
+    }
+
+    self.engineWebView = wkWebView;
+
+    if ([self.viewController conformsToProtocol:@protocol(WKUIDelegate)]) {
+        wkWebView.UIDelegate = (id <WKUIDelegate>)self.viewController;
+    }
+
+    if ([self.viewController conformsToProtocol:@protocol(WKNavigationDelegate)]) {
+        wkWebView.navigationDelegate = (id <WKNavigationDelegate>)self.viewController;
+    } else {
+        wkWebView.navigationDelegate = (id <WKNavigationDelegate>)self;
+    }
+
+    if ([self.viewController conformsToProtocol:@protocol(WKScriptMessageHandler)]) {
+        [wkWebView.configuration.userContentController addScriptMessageHandler:(id < WKScriptMessageHandler >)self.viewController name:CDV_BRIDGE_NAME];
+    }
+
+    [self updateSettings:settings];
+
+    // check if content thread has died on resume
+    NSLog(@"%@", @"CDVWebViewEngine will reload WKWebView if required on resume");
+    [[NSNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(onAppWillEnterForeground:)
+               name:UIApplicationWillEnterForegroundNotification object:nil];
+
+    NSLog(@"Using WKWebView");
+
+    [self addURLObserver];
+}
+
+- (void)onReset {
+    [self addURLObserver];
+}
+
+static void * KVOContext = &KVOContext;
+
+- (void)addURLObserver {
+    if(!IsAtLeastiOSVersion(@"9.0")){
+        [self.webView addObserver:self forKeyPath:@"URL" options:0 context:KVOContext];
+    }
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
+{
+    if (context == KVOContext) {
+        if (object == [self webView] && [keyPath isEqualToString: @"URL"] && [object valueForKeyPath:keyPath] == nil){
+            NSLog(@"URL is nil. Reloading WKWebView");
+            [(WKWebView*)_engineWebView reload];
+        }
+    } else {
+        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+    }
+}
+
+- (void) onAppWillEnterForeground:(NSNotification*)notification {
+    if ([self shouldReloadWebView]) {
+        NSLog(@"%@", @"CDVWebViewEngine reloading!");
+        [(WKWebView*)_engineWebView reload];
+    }
+}
+
+- (BOOL)shouldReloadWebView
+{
+    WKWebView* wkWebView = (WKWebView*)_engineWebView;
+    return [self shouldReloadWebView:wkWebView.URL title:wkWebView.title];
+}
+
+- (BOOL)shouldReloadWebView:(NSURL*)location title:(NSString*)title
+{
+    BOOL title_is_nil = (title == nil);
+    BOOL location_is_blank = [[location absoluteString] isEqualToString:@"about:blank"];
+
+    BOOL reload = (title_is_nil || location_is_blank);
+
+#ifdef DEBUG
+    NSLog(@"%@", @"CDVWebViewEngine shouldReloadWebView::");
+    NSLog(@"CDVWebViewEngine shouldReloadWebView title: %@", title);
+    NSLog(@"CDVWebViewEngine shouldReloadWebView location: %@", [location absoluteString]);
+    NSLog(@"CDVWebViewEngine shouldReloadWebView reload: %u", reload);
+#endif
+
+    return reload;
+}
+
+
+- (id)loadRequest:(NSURLRequest*)request
+{
+    if ([self canLoadRequest:request]) { // can load, differentiate between file urls and other schemes
+        if(request.URL.fileURL && self.cdvIsFileScheme) {
+            NSURL* readAccessUrl = [request.URL URLByDeletingLastPathComponent];
+            return [(WKWebView*)_engineWebView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl];
+        } else if (request.URL.fileURL) {
+            NSURL* startURL = [NSURL URLWithString:((CDVViewController *)self.viewController).startPage];
+            NSString* startFilePath = [self.commandDelegate pathForResource:[startURL path]];
+            NSURL *url = [[NSURL URLWithString:self.CDV_ASSETS_URL] URLByAppendingPathComponent:request.URL.path];
+            if ([request.URL.path isEqualToString:startFilePath]) {
+                url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.CDV_ASSETS_URL, startURL]];
+            }
+            if(request.URL.query) {
+                url = [NSURL URLWithString:[@"?" stringByAppendingString:request.URL.query] relativeToURL:url];
+            }
+            if(request.URL.fragment) {
+                url = [NSURL URLWithString:[@"#" stringByAppendingString:request.URL.fragment] relativeToURL:url];
+            }
+            request = [NSURLRequest requestWithURL:url];
+        }
+        return [(WKWebView*)_engineWebView loadRequest:request];
+    } else { // can't load, print out error
+        NSString* errorHtml = [NSString stringWithFormat:
+                               @"<!doctype html>"
+                               @"<title>Error</title>"
+                               @"<div style='font-size:2em'>"
+                               @"   <p>The WebView engine '%@' is unable to load the request: %@</p>"
+                               @"   <p>Most likely the cause of the error is that the loading of file urls is not supported in iOS %@.</p>"
+                               @"</div>",
+                               NSStringFromClass([self class]),
+                               [request.URL description],
+                               [[UIDevice currentDevice] systemVersion]
+                               ];
+        return [self loadHTMLString:errorHtml baseURL:nil];
+    }
+}
+
+- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL
+{
+    return [(WKWebView*)_engineWebView loadHTMLString:string baseURL:baseURL];
+}
+
+- (NSURL*) URL
+{
+    return [(WKWebView*)_engineWebView URL];
+}
+
+- (BOOL) canLoadRequest:(NSURLRequest*)request
+{
+    // See: https://issues.apache.org/jira/browse/CB-9636
+    SEL wk_sel = NSSelectorFromString(CDV_WKWEBVIEW_FILE_URL_LOAD_SELECTOR);
+
+    // if it's a file URL, check whether WKWebView has the selector (which is in iOS 9 and up only)
+    if (request.URL.fileURL) {
+        return [_engineWebView respondsToSelector:wk_sel];
+    } else {
+        return YES;
+    }
+}
+
+- (void)updateSettings:(NSDictionary*)settings
+{
+    WKWebView* wkWebView = (WKWebView*)_engineWebView;
+
+    wkWebView.configuration.preferences.minimumFontSize = [settings cordovaFloatSettingForKey:@"MinimumFontSize" defaultValue:0.0];
+
+    /*
+     wkWebView.configuration.preferences.javaScriptEnabled = [settings cordovaBoolSettingForKey:@"JavaScriptEnabled" default:YES];
+     wkWebView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = [settings cordovaBoolSettingForKey:@"JavaScriptCanOpenWindowsAutomatically" default:NO];
+     */
+
+    // By default, DisallowOverscroll is false (thus bounce is allowed)
+    BOOL bounceAllowed = !([settings cordovaBoolSettingForKey:@"DisallowOverscroll" defaultValue:NO]);
+
+    // prevent webView from bouncing
+    if (!bounceAllowed) {
+        if ([wkWebView respondsToSelector:@selector(scrollView)]) {
+            ((UIScrollView*)[wkWebView scrollView]).bounces = NO;
+        } else {
+            for (id subview in wkWebView.subviews) {
+                if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
+                    ((UIScrollView*)subview).bounces = NO;
+                }
+            }
+        }
+    }
+
+    NSString* decelerationSetting = [settings cordovaSettingForKey:@"WKWebViewDecelerationSpeed"];
+
+    if (![@"fast" isEqualToString:decelerationSetting]) {
+        [wkWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal];
+    } else {
+        [wkWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateFast];
+    }
+
+    wkWebView.allowsBackForwardNavigationGestures = [settings cordovaBoolSettingForKey:@"AllowBackForwardNavigationGestures" defaultValue:NO];
+    wkWebView.allowsLinkPreview = [settings cordovaBoolSettingForKey:@"Allow3DTouchLinkPreview" defaultValue:YES];
+}
+
+- (void)updateWithInfo:(NSDictionary*)info
+{
+    NSDictionary* scriptMessageHandlers = [info objectForKey:kCDVWebViewEngineScriptMessageHandlers];
+    NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences];
+    id navigationDelegate = [info objectForKey:kCDVWebViewEngineWKNavigationDelegate];
+    id uiDelegate = [info objectForKey:kCDVWebViewEngineWKUIDelegate];
+
+    WKWebView* wkWebView = (WKWebView*)_engineWebView;
+
+    if (scriptMessageHandlers && [scriptMessageHandlers isKindOfClass:[NSDictionary class]]) {
+        NSArray* allKeys = [scriptMessageHandlers allKeys];
+
+        for (NSString* key in allKeys) {
+            id object = [scriptMessageHandlers objectForKey:key];
+            if ([object conformsToProtocol:@protocol(WKScriptMessageHandler)]) {
+                [wkWebView.configuration.userContentController addScriptMessageHandler:object name:key];
+            }
+        }
+    }
+
+    if (navigationDelegate && [navigationDelegate conformsToProtocol:@protocol(WKNavigationDelegate)]) {
+        wkWebView.navigationDelegate = navigationDelegate;
+    }
+
+    if (uiDelegate && [uiDelegate conformsToProtocol:@protocol(WKUIDelegate)]) {
+        wkWebView.UIDelegate = uiDelegate;
+    }
+
+    if (settings && [settings isKindOfClass:[NSDictionary class]]) {
+        [self updateSettings:settings];
+    }
+}
+
+// This forwards the methods that are in the header that are not implemented here.
+// Both WKWebView implement the below:
+//     loadHTMLString:baseURL:
+//     loadRequest:
+- (id)forwardingTargetForSelector:(SEL)aSelector
+{
+    return _engineWebView;
+}
+
+- (UIView*)webView
+{
+    return self.engineWebView;
+}
+
+#pragma mark WKScriptMessageHandler implementation
+
+- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message
+{
+    if (![message.name isEqualToString:CDV_BRIDGE_NAME]) {
+        return;
+    }
+
+    CDVViewController* vc = (CDVViewController*)self.viewController;
+
+    NSArray* jsonEntry = message.body; // NSString:callbackId, NSString:service, NSString:action, NSArray:args
+    CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
+    CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName);
+
+    if (![vc.commandQueue execute:command]) {
+#ifdef DEBUG
+        NSError* error = nil;
+        NSString* commandJson = nil;
+        NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonEntry
+                                                           options:0
+                                                             error:&error];
+
+        if (error == nil) {
+            commandJson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+        }
+
+            static NSUInteger maxLogLength = 1024;
+            NSString* commandString = ([commandJson length] > maxLogLength) ?
+                [NSString stringWithFormat : @"%@[...]", [commandJson substringToIndex:maxLogLength]] :
+                commandJson;
+
+            NSLog(@"FAILED pluginJSON = %@", commandString);
+#endif
+    }
+}
+
+#pragma mark WKNavigationDelegate implementation
+
+- (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(WKNavigation*)navigation
+{
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:webView]];
+}
+
+- (void)webView:(WKWebView*)webView didFinishNavigation:(WKNavigation*)navigation
+{
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:webView]];
+}
+
+- (void)webView:(WKWebView*)theWebView didFailProvisionalNavigation:(WKNavigation*)navigation withError:(NSError*)error
+{
+    [self webView:theWebView didFailNavigation:navigation withError:error];
+}
+
+- (void)webView:(WKWebView*)theWebView didFailNavigation:(WKNavigation*)navigation withError:(NSError*)error
+{
+    CDVViewController* vc = (CDVViewController*)self.viewController;
+
+    NSString* message = [NSString stringWithFormat:@"Failed to load webpage with error: %@", [error localizedDescription]];
+    NSLog(@"%@", message);
+
+    NSURL* errorUrl = vc.errorURL;
+    if (errorUrl) {
+        NSCharacterSet *charSet = [NSCharacterSet URLFragmentAllowedCharacterSet];
+        errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [message stringByAddingPercentEncodingWithAllowedCharacters:charSet]] relativeToURL:errorUrl];
+        NSLog(@"%@", [errorUrl absoluteString]);
+        [theWebView loadRequest:[NSURLRequest requestWithURL:errorUrl]];
+    }
+}
+
+- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
+{
+    [webView reload];
+}
+
+- (BOOL)defaultResourcePolicyForURL:(NSURL*)url
+{
+    // all file:// urls are allowed
+    if ([url isFileURL]) {
+        return YES;
+    }
+
+    return NO;
+}
+
+- (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction*) navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy)) decisionHandler
+{
+    NSURL* url = [navigationAction.request URL];
+    CDVViewController* vc = (CDVViewController*)self.viewController;
+
+    /*
+     * Give plugins the chance to handle the url
+     */
+    BOOL anyPluginsResponded = NO;
+    BOOL shouldAllowRequest = NO;
+
+    for (NSString* pluginName in vc.pluginObjects) {
+        CDVPlugin* plugin = [vc.pluginObjects objectForKey:pluginName];
+        SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:");
+        if ([plugin respondsToSelector:selector]) {
+            anyPluginsResponded = YES;
+            // https://issues.apache.org/jira/browse/CB-12497
+            int navType = (int)navigationAction.navigationType;
+            shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, navigationAction.request, navType));
+            if (!shouldAllowRequest) {
+                break;
+            }
+        }
+    }
+
+    if (anyPluginsResponded) {
+        return decisionHandler(shouldAllowRequest);
+    }
+
+    /*
+     * Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
+     */
+    BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url];
+    if (shouldAllowNavigation) {
+        return decisionHandler(YES);
+    } else {
+        [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
+    }
+
+    return decisionHandler(NO);
+}
+
+#pragma mark - Plugin interface
+
+- (void)allowsBackForwardNavigationGestures:(CDVInvokedUrlCommand*)command;
+{
+    id value = [command argumentAtIndex:0];
+    if (!([value isKindOfClass:[NSNumber class]])) {
+        value = [NSNumber numberWithBool:NO];
+    }
+
+    WKWebView* wkWebView = (WKWebView*)_engineWebView;
+    wkWebView.allowsBackForwardNavigationGestures = [value boolValue];
+}
+
+@end
+
+#pragma mark - CDVWebViewWeakScriptMessageHandler
+
+@implementation CDVWebViewWeakScriptMessageHandler
+
+- (instancetype)initWithScriptMessageHandler:(id<WKScriptMessageHandler>)scriptMessageHandler
+{
+    self = [super init];
+    if (self) {
+        _scriptMessageHandler = scriptMessageHandler;
+    }
+    return self;
+}
+
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    [self.scriptMessageHandler userContentController:userContentController didReceiveScriptMessage:message];
+}
+
+@end

+ 27 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.h

@@ -0,0 +1,27 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <WebKit/WebKit.h>
+
+@interface CDVWebViewProcessPoolFactory : NSObject
+@property (nonatomic, retain) WKProcessPool* sharedPool;
+
++(instancetype) sharedFactory;
+-(WKProcessPool*) sharedProcessPool;
+@end

+ 49 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewProcessPoolFactory.m

@@ -0,0 +1,49 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WebKit/WebKit.h>
+#import "CDVWebViewProcessPoolFactory.h"
+
+static CDVWebViewProcessPoolFactory *factory = nil;
+
+@implementation CDVWebViewProcessPoolFactory
+
++ (instancetype)sharedFactory
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        factory = [[CDVWebViewProcessPoolFactory alloc] init];
+    });
+    
+    return factory;
+}
+
+- (instancetype)init
+{
+    if (self = [super init]) {
+        _sharedPool = [[WKProcessPool alloc] init];
+    }
+    return self;
+}
+
+- (WKProcessPool*) sharedProcessPool {
+    return _sharedPool;
+}
+@end

+ 32 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.h

@@ -0,0 +1,32 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <WebKit/WebKit.h>
+
+@interface CDVWebViewUIDelegate : NSObject <WKUIDelegate>
+{
+    NSMutableArray<UIViewController*>* windows;
+}
+
+@property (nonatomic, copy) NSString* title;
+@property (nonatomic, assign) BOOL allowNewWindows;
+
+- (instancetype)initWithTitle:(NSString*)title;
+
+@end

+ 163 - 0
cordova/platforms/ios/CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewUIDelegate.m

@@ -0,0 +1,163 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVWebViewUIDelegate.h"
+
+@implementation CDVWebViewUIDelegate
+
+- (instancetype)initWithTitle:(NSString*)title
+{
+    self = [super init];
+    if (self) {
+        self.title = title;
+        windows = [[NSMutableArray alloc] init];
+    }
+
+    return self;
+}
+
+- (void)     webView:(WKWebView*)webView runJavaScriptAlertPanelWithMessage:(NSString*)message
+    initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(void))completionHandler
+{
+    UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
+                                                                   message:message
+                                                            preferredStyle:UIAlertControllerStyleAlert];
+
+    UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
+                                                 style:UIAlertActionStyleDefault
+                                               handler:^(UIAlertAction* action)
+        {
+            completionHandler();
+            [alert dismissViewControllerAnimated:YES completion:nil];
+        }];
+
+    [alert addAction:ok];
+
+    UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController;
+
+    [rootController presentViewController:alert animated:YES completion:nil];
+}
+
+- (void)     webView:(WKWebView*)webView runJavaScriptConfirmPanelWithMessage:(NSString*)message
+    initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(BOOL result))completionHandler
+{
+    UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
+                                                                   message:message
+                                                            preferredStyle:UIAlertControllerStyleAlert];
+
+    UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
+                                                 style:UIAlertActionStyleDefault
+                                               handler:^(UIAlertAction* action)
+        {
+            completionHandler(YES);
+            [alert dismissViewControllerAnimated:YES completion:nil];
+        }];
+
+    [alert addAction:ok];
+
+    UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel")
+                                                     style:UIAlertActionStyleDefault
+                                                   handler:^(UIAlertAction* action)
+        {
+            completionHandler(NO);
+            [alert dismissViewControllerAnimated:YES completion:nil];
+        }];
+    [alert addAction:cancel];
+
+    UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController;
+
+    [rootController presentViewController:alert animated:YES completion:nil];
+}
+
+- (void)      webView:(WKWebView*)webView runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
+          defaultText:(NSString*)defaultText initiatedByFrame:(WKFrameInfo*)frame
+    completionHandler:(void (^)(NSString* result))completionHandler
+{
+    UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
+                                                                   message:prompt
+                                                            preferredStyle:UIAlertControllerStyleAlert];
+
+    UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
+                                                 style:UIAlertActionStyleDefault
+                                               handler:^(UIAlertAction* action)
+        {
+            completionHandler(((UITextField*)alert.textFields[0]).text);
+            [alert dismissViewControllerAnimated:YES completion:nil];
+        }];
+
+    [alert addAction:ok];
+
+    UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel")
+                                                     style:UIAlertActionStyleDefault
+                                                   handler:^(UIAlertAction* action)
+        {
+            completionHandler(nil);
+            [alert dismissViewControllerAnimated:YES completion:nil];
+        }];
+    [alert addAction:cancel];
+
+    [alert addTextFieldWithConfigurationHandler:^(UITextField* textField) {
+        textField.text = defaultText;
+    }];
+
+    UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController;
+
+    [rootController presentViewController:alert animated:YES completion:nil];
+}
+
+- (WKWebView*) webView:(WKWebView*)webView createWebViewWithConfiguration:(WKWebViewConfiguration*)configuration forNavigationAction:(WKNavigationAction*)navigationAction windowFeatures:(WKWindowFeatures*)windowFeatures
+{
+    if (!navigationAction.targetFrame.isMainFrame) {
+        if (self.allowNewWindows) {
+            WKWebView* v = [[WKWebView alloc] initWithFrame:webView.frame configuration:configuration];
+            v.UIDelegate = webView.UIDelegate;
+            v.navigationDelegate = webView.navigationDelegate;
+
+            UIViewController* vc = [[UIViewController alloc] init];
+            vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
+            vc.view = v;
+
+            [windows addObject:vc];
+
+            UIViewController* rootController = [UIApplication sharedApplication].delegate.window.rootViewController;
+            [rootController presentViewController:vc animated:YES completion:nil];
+            return v;
+        } else {
+            [webView loadRequest:navigationAction.request];
+        }
+    }
+
+    return nil;
+}
+
+- (void)webViewDidClose:(WKWebView*)webView
+{
+    for (UIViewController* vc in windows) {
+        if (vc.view == webView) {
+            [vc dismissViewControllerAnimated:YES completion:nil];
+            [windows removeObject:vc];
+            break;
+        }
+    }
+
+    // We do not allow closing the primary WebView
+}
+
+
+@end

+ 30 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDV.h

@@ -0,0 +1,30 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVAvailability.h"
+#import "CDVAvailabilityDeprecated.h"
+#import "CDVAppDelegate.h"
+#import "CDVPlugin.h"
+#import "CDVPluginResult.h"
+#import "CDVViewController.h"
+#import "CDVCommandDelegate.h"
+#import "CDVInvokedUrlCommand.h"
+#import "CDVWhitelist.h"
+#import "CDVScreenOrientationDelegate.h"
+#import "CDVTimer.h"

+ 28 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVAppDelegate.h

@@ -0,0 +1,28 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import "CDVViewController.h"
+
+@interface CDVAppDelegate : NSObject <UIApplicationDelegate>{}
+
+@property (nonatomic, strong) IBOutlet UIWindow* window;
+@property (nonatomic, strong) IBOutlet CDVViewController* viewController;
+
+@end

+ 97 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVAppDelegate.m

@@ -0,0 +1,97 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVAppDelegate.h"
+
+@implementation CDVAppDelegate
+
+@synthesize window, viewController;
+
+- (id)init
+{
+    self = [super init];
+    return self;
+}
+
+#pragma mark UIApplicationDelegate implementation
+
+/**
+ * This is main kick off after the app inits, the views and Settings are setup here. (preferred - iOS4 and up)
+ */
+- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
+{
+    CGRect screenBounds = [[UIScreen mainScreen] bounds];
+
+    self.window = [[UIWindow alloc] initWithFrame:screenBounds];
+    self.window.autoresizesSubviews = YES;
+
+    // only set if not already set in subclass
+    if (self.viewController == nil) {
+        self.viewController = [[CDVViewController alloc] init];
+    }
+
+    // Set your app's start page by setting the <content src='foo.html' /> tag in config.xml.
+    // If necessary, uncomment the line below to override it.
+    // self.viewController.startPage = @"index.html";
+
+    // NOTE: To customize the view's frame size (which defaults to full screen), override
+    // [self.viewController viewWillAppear:] in your view controller.
+
+    self.window.rootViewController = self.viewController;
+    [self.window makeKeyAndVisible];
+
+    return YES;
+}
+
+// this happens while we are running ( in the background, or from within our own app )
+// only valid if 40x-Info.plist specifies a protocol to handle
+- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
+{
+    if (!url) {
+        return NO;
+    }
+
+    NSMutableDictionary * openURLData = [[NSMutableDictionary alloc] init];
+
+    [openURLData setValue:url forKey:@"url"];
+
+    if (options[UIApplicationOpenURLOptionsSourceApplicationKey]) {
+        [openURLData setValue:options[UIApplicationOpenURLOptionsSourceApplicationKey] forKey:@"sourceApplication"];
+    }
+
+    if (options[UIApplicationOpenURLOptionsAnnotationKey]) {
+        [openURLData setValue:options[UIApplicationOpenURLOptionsAnnotationKey] forKey:@"annotation"];
+    }
+
+    // all plugins will get the notification, and their handlers will be called
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification object:openURLData]];
+
+    return YES;
+}
+
+- (UIInterfaceOrientationMask)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
+{
+    // iPhone doesn't support upside down by default, while the iPad does.  Override to allow all orientations always, and let the root view controller decide what's allowed (the supported orientations mask gets intersected).
+    NSUInteger supportedInterfaceOrientations = (1 << UIInterfaceOrientationPortrait) | (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight) | (1 << UIInterfaceOrientationPortraitUpsideDown);
+
+    return supportedInterfaceOrientations;
+}
+
+@end

+ 118 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVAvailability.h

@@ -0,0 +1,118 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVAvailabilityDeprecated.h"
+
+#define __CORDOVA_IOS__
+
+#define __CORDOVA_0_9_6 906
+#define __CORDOVA_1_0_0 10000
+#define __CORDOVA_1_1_0 10100
+#define __CORDOVA_1_2_0 10200
+#define __CORDOVA_1_3_0 10300
+#define __CORDOVA_1_4_0 10400
+#define __CORDOVA_1_4_1 10401
+#define __CORDOVA_1_5_0 10500
+#define __CORDOVA_1_6_0 10600
+#define __CORDOVA_1_6_1 10601
+#define __CORDOVA_1_7_0 10700
+#define __CORDOVA_1_8_0 10800
+#define __CORDOVA_1_8_1 10801
+#define __CORDOVA_1_9_0 10900
+#define __CORDOVA_2_0_0 20000
+#define __CORDOVA_2_1_0 20100
+#define __CORDOVA_2_2_0 20200
+#define __CORDOVA_2_3_0 20300
+#define __CORDOVA_2_4_0 20400
+#define __CORDOVA_2_5_0 20500
+#define __CORDOVA_2_6_0 20600
+#define __CORDOVA_2_7_0 20700
+#define __CORDOVA_2_8_0 20800
+#define __CORDOVA_2_9_0 20900
+#define __CORDOVA_3_0_0 30000
+#define __CORDOVA_3_1_0 30100
+#define __CORDOVA_3_2_0 30200
+#define __CORDOVA_3_3_0 30300
+#define __CORDOVA_3_4_0 30400
+#define __CORDOVA_3_4_1 30401
+#define __CORDOVA_3_5_0 30500
+#define __CORDOVA_3_6_0 30600
+#define __CORDOVA_3_7_0 30700
+#define __CORDOVA_3_8_0 30800
+#define __CORDOVA_3_9_0 30900
+#define __CORDOVA_3_9_1 30901
+#define __CORDOVA_3_9_2 30902
+#define __CORDOVA_4_0_0 40000
+#define __CORDOVA_4_0_1 40001
+#define __CORDOVA_4_1_0 40100
+#define __CORDOVA_4_1_1 40101
+#define __CORDOVA_4_2_0 40200
+#define __CORDOVA_4_2_1 40201
+#define __CORDOVA_4_3_0 40300
+#define __CORDOVA_4_3_1 40301
+#define __CORDOVA_4_4_0 40400
+#define __CORDOVA_4_5_0 40500
+#define __CORDOVA_4_5_1 40501
+#define __CORDOVA_4_5_2 40502
+#define __CORDOVA_4_5_4 40504
+#define __CORDOVA_5_0_0 50000
+#define __CORDOVA_5_0_1 50001
+#define __CORDOVA_5_1_0 50100
+#define __CORDOVA_5_1_1 50101
+#define __CORDOVA_6_0_0 60000
+#define __CORDOVA_6_1_0 60100
+#define __CORDOVA_6_1_1 60101
+/* coho:next-version,insert-before */
+#define __CORDOVA_NA 99999      /* not available */
+
+/*
+ #if CORDOVA_VERSION_MIN_REQUIRED >= __CORDOVA_4_0_0
+    // do something when its at least 4.0.0
+ #else
+    // do something else (non 4.0.0)
+ #endif
+ */
+#ifndef CORDOVA_VERSION_MIN_REQUIRED
+    /* coho:next-version-min-required,replace-after */
+    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_6_1_1
+#endif
+
+/*
+ Returns YES if it is at least version specified as NSString(X)
+ Usage:
+     if (IsAtLeastiOSVersion(@"5.1")) {
+         // do something for iOS 5.1 or greater
+     }
+ */
+#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending)
+
+/* Return the string version of the decimal version */
+#define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \
+    (CORDOVA_VERSION_MIN_REQUIRED / 10000),                 \
+    (CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100,           \
+    (CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100]
+
+// Enable this to log all exec() calls.
+#define CDV_ENABLE_EXEC_LOGGING 0
+#if CDV_ENABLE_EXEC_LOGGING
+    #define CDV_EXEC_LOG NSLog
+#else
+    #define CDV_EXEC_LOG(...) do { \
+} while (NO)
+#endif

+ 26 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVAvailabilityDeprecated.h

@@ -0,0 +1,26 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+#ifdef __clang__
+    #define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg)))
+#else
+    #define CDV_DEPRECATED(version, msg) __attribute__((deprecated()))
+#endif

+ 49 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandDelegate.h

@@ -0,0 +1,49 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVAvailability.h"
+#import "CDVInvokedUrlCommand.h"
+
+@class CDVPlugin;
+@class CDVPluginResult;
+@class CDVWhitelist;
+
+typedef NSURL* (^ UrlTransformerBlock)(NSURL*);
+
+@protocol CDVCommandDelegate <NSObject>
+
+@property (nonatomic, readonly) NSDictionary* settings;
+@property (nonatomic, copy) UrlTransformerBlock urlTransformer;
+
+- (NSString*)pathForResource:(NSString*)resourcepath;
+- (id)getCommandInstance:(NSString*)pluginName;
+
+// Sends a plugin result to the JS. This is thread-safe.
+- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId;
+// Evaluates the given JS. This is thread-safe.
+- (void)evalJs:(NSString*)js;
+// Can be used to evaluate JS right away instead of scheduling it on the run-loop.
+// This is required for dispatch resign and pause events, but should not be used
+// without reason. Without the run-loop delay, alerts used in JS callbacks may result
+// in dead-lock. This method must be called from the UI thread.
+- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop;
+// Runs the given block on a background thread using a shared thread-pool.
+- (void)runInBackground:(void (^)(void))block;
+
+@end

+ 36 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandDelegateImpl.h

@@ -0,0 +1,36 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import "CDVCommandDelegate.h"
+
+@class CDVViewController;
+@class CDVCommandQueue;
+
+@interface CDVCommandDelegateImpl : NSObject <CDVCommandDelegate>{
+    @private
+    __weak CDVViewController* _viewController;
+    NSRegularExpression* _callbackIdPattern;
+    @protected
+    __weak CDVCommandQueue* _commandQueue;
+    BOOL _delayResponses;
+}
+- (id)initWithViewController:(CDVViewController*)viewController;
+- (void)flushCommandQueueWithDelayedJs;
+@end

+ 181 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandDelegateImpl.m

@@ -0,0 +1,181 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVCommandDelegateImpl.h"
+#import "CDVJSON_private.h"
+#import "CDVCommandQueue.h"
+#import "CDVPluginResult.h"
+#import "CDVViewController.h"
+
+@implementation CDVCommandDelegateImpl
+
+@synthesize urlTransformer;
+
+- (id)initWithViewController:(CDVViewController*)viewController
+{
+    self = [super init];
+    if (self != nil) {
+        _viewController = viewController;
+        _commandQueue = _viewController.commandQueue;
+
+        NSError* err = nil;
+        _callbackIdPattern = [NSRegularExpression regularExpressionWithPattern:@"[^A-Za-z0-9._-]" options:0 error:&err];
+        if (err != nil) {
+            // Couldn't initialize Regex
+            NSLog(@"Error: Couldn't initialize regex");
+            _callbackIdPattern = nil;
+        }
+    }
+    return self;
+}
+
+- (NSString*)pathForResource:(NSString*)resourcepath
+{
+    NSBundle* mainBundle = [NSBundle mainBundle];
+    NSMutableArray* directoryParts = [NSMutableArray arrayWithArray:[resourcepath componentsSeparatedByString:@"/"]];
+    NSString* filename = [directoryParts lastObject];
+
+    [directoryParts removeLastObject];
+
+    NSString* directoryPartsJoined = [directoryParts componentsJoinedByString:@"/"];
+    NSString* directoryStr = _viewController.wwwFolderName;
+
+    if ([directoryPartsJoined length] > 0) {
+        directoryStr = [NSString stringWithFormat:@"%@/%@", _viewController.wwwFolderName, [directoryParts componentsJoinedByString:@"/"]];
+    }
+
+    return [mainBundle pathForResource:filename ofType:@"" inDirectory:directoryStr];
+}
+
+- (void)flushCommandQueueWithDelayedJs
+{
+    _delayResponses = YES;
+    [_commandQueue executePending];
+    _delayResponses = NO;
+}
+
+- (void)evalJsHelper2:(NSString*)js
+{
+    CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]);
+    [_viewController.webViewEngine evaluateJavaScript:js completionHandler:^(id obj, NSError* error) {
+        // TODO: obj can be something other than string
+        if ([obj isKindOfClass:[NSString class]]) {
+            NSString* commandsJSON = (NSString*)obj;
+            if ([commandsJSON length] > 0) {
+                CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining.");
+            }
+
+            [self->_commandQueue enqueueCommandBatch:commandsJSON];
+            [self->_commandQueue executePending];
+        }
+    }];
+}
+
+- (void)evalJsHelper:(NSString*)js
+{
+    // Cycle the run-loop before executing the JS.
+    // For _delayResponses -
+    //    This ensures that we don't eval JS during the middle of an existing JS
+    //    function (possible since WKWebViewDelegate callbacks can be synchronous).
+    // For !isMainThread -
+    //    It's a hard error to eval on the non-UI thread.
+    // For !_commandQueue.currentlyExecuting -
+    //     This works around a bug where sometimes alerts() within callbacks can cause
+    //     dead-lock.
+    //     If the commandQueue is currently executing, then we know that it is safe to
+    //     execute the callback immediately.
+    // Using    (dispatch_get_main_queue()) does *not* fix deadlocks for some reason,
+    // but performSelectorOnMainThread: does.
+    if (_delayResponses || ![NSThread isMainThread] || !_commandQueue.currentlyExecuting) {
+        [self performSelectorOnMainThread:@selector(evalJsHelper2:) withObject:js waitUntilDone:NO];
+    } else {
+        [self evalJsHelper2:js];
+    }
+}
+
+- (BOOL)isValidCallbackId:(NSString*)callbackId
+{
+    if ((callbackId == nil) || (_callbackIdPattern == nil)) {
+        return NO;
+    }
+
+    // Disallow if too long or if any invalid characters were found.
+    if (([callbackId length] > 100) || [_callbackIdPattern firstMatchInString:callbackId options:0 range:NSMakeRange(0, [callbackId length])]) {
+        return NO;
+    }
+    return YES;
+}
+
+- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId
+{
+    CDV_EXEC_LOG(@"Exec(%@): Sending result. Status=%@", callbackId, result.status);
+    // This occurs when there is are no win/fail callbacks for the call.
+    if ([@"INVALID" isEqualToString:callbackId]) {
+        return;
+    }
+    // This occurs when the callback id is malformed.
+    if (![self isValidCallbackId:callbackId]) {
+        NSLog(@"Invalid callback id received by sendPluginResult");
+        return;
+    }
+    int status = [result.status intValue];
+    BOOL keepCallback = [result.keepCallback boolValue];
+    NSString* argumentsAsJSON = [result argumentsAsJSON];
+    BOOL debug = NO;
+    
+#ifdef DEBUG
+    debug = YES;
+#endif
+
+    NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d, %d)", callbackId, status, argumentsAsJSON, keepCallback, debug];
+
+    [self evalJsHelper:js];
+}
+
+- (void)evalJs:(NSString*)js
+{
+    [self evalJs:js scheduledOnRunLoop:YES];
+}
+
+- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop
+{
+    js = [NSString stringWithFormat:@"try{cordova.require('cordova/exec').nativeEvalAndFetch(function(){%@})}catch(e){console.log('exception nativeEvalAndFetch : '+e);};", js];
+    if (scheduledOnRunLoop) {
+        [self evalJsHelper:js];
+    } else {
+        [self evalJsHelper2:js];
+    }
+}
+
+- (id)getCommandInstance:(NSString*)pluginName
+{
+    return [_viewController getCommandInstance:pluginName];
+}
+
+- (void)runInBackground:(void (^)(void))block
+{
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
+}
+
+- (NSDictionary*)settings
+{
+    return _viewController.settings;
+}
+
+@end

+ 39 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandQueue.h

@@ -0,0 +1,39 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class CDVInvokedUrlCommand;
+@class CDVViewController;
+
+@interface CDVCommandQueue : NSObject
+
+@property (nonatomic, readonly) BOOL currentlyExecuting;
+
+- (id)initWithViewController:(CDVViewController*)viewController;
+- (void)dispose;
+
+- (void)resetRequestId;
+- (void)enqueueCommandBatch:(NSString*)batchJSON;
+
+- (void)fetchCommandsFromJs;
+- (void)executePending;
+- (BOOL)execute:(CDVInvokedUrlCommand*)command;
+
+@end

+ 194 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVCommandQueue.m

@@ -0,0 +1,194 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#include <objc/message.h>
+#import "CDVCommandQueue.h"
+#import "CDVViewController.h"
+#import "CDVCommandDelegateImpl.h"
+#import "CDVJSON_private.h"
+#import "CDVDebug.h"
+
+// Parse JS on the main thread if it's shorter than this.
+static const NSInteger JSON_SIZE_FOR_MAIN_THREAD = 4 * 1024; // Chosen arbitrarily.
+// Execute multiple commands in one go until this many seconds have passed.
+static const double MAX_EXECUTION_TIME = .008; // Half of a 60fps frame.
+
+@interface CDVCommandQueue () {
+    NSInteger _lastCommandQueueFlushRequestId;
+    __weak CDVViewController* _viewController;
+    NSMutableArray* _queue;
+    NSTimeInterval _startExecutionTime;
+}
+@end
+
+@implementation CDVCommandQueue
+
+- (BOOL)currentlyExecuting
+{
+    return _startExecutionTime > 0;
+}
+
+- (id)initWithViewController:(CDVViewController*)viewController
+{
+    self = [super init];
+    if (self != nil) {
+        _viewController = viewController;
+        _queue = [[NSMutableArray alloc] init];
+    }
+    return self;
+}
+
+- (void)dispose
+{
+    // TODO(agrieve): Make this a zeroing weak ref once we drop support for 4.3.
+    _viewController = nil;
+}
+
+- (void)resetRequestId
+{
+    _lastCommandQueueFlushRequestId = 0;
+}
+
+- (void)enqueueCommandBatch:(NSString*)batchJSON
+{
+    if ([batchJSON length] > 0) {
+        NSMutableArray* commandBatchHolder = [[NSMutableArray alloc] init];
+        [_queue addObject:commandBatchHolder];
+        if ([batchJSON length] < JSON_SIZE_FOR_MAIN_THREAD) {
+            [commandBatchHolder addObject:[batchJSON cdv_JSONObject]];
+        } else {
+            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
+                NSMutableArray* result = [batchJSON cdv_JSONObject];
+                @synchronized(commandBatchHolder) {
+                    [commandBatchHolder addObject:result];
+                }
+                [self performSelectorOnMainThread:@selector(executePending) withObject:nil waitUntilDone:NO];
+            });
+        }
+    }
+}
+
+- (void)fetchCommandsFromJs
+{
+    __weak CDVCommandQueue* weakSelf = self;
+    NSString* js = @"cordova.require('cordova/exec').nativeFetchMessages()";
+
+    [_viewController.webViewEngine evaluateJavaScript:js
+                                    completionHandler:^(id obj, NSError* error) {
+        if ((error == nil) && [obj isKindOfClass:[NSString class]]) {
+            NSString* queuedCommandsJSON = (NSString*)obj;
+            CDV_EXEC_LOG(@"Exec: Flushed JS->native queue (hadCommands=%d).", [queuedCommandsJSON length] > 0);
+            [weakSelf enqueueCommandBatch:queuedCommandsJSON];
+            // this has to be called here now, because fetchCommandsFromJs is now async (previously: synchronous)
+            [self executePending];
+        }
+    }];
+}
+
+- (void)executePending
+{
+    // Make us re-entrant-safe.
+    if (_startExecutionTime > 0) {
+        return;
+    }
+    @try {
+        _startExecutionTime = [NSDate timeIntervalSinceReferenceDate];
+
+        while ([_queue count] > 0) {
+            NSMutableArray* commandBatchHolder = _queue[0];
+            NSMutableArray* commandBatch = nil;
+            @synchronized(commandBatchHolder) {
+                // If the next-up command is still being decoded, wait for it.
+                if ([commandBatchHolder count] == 0) {
+                    break;
+                }
+                commandBatch = commandBatchHolder[0];
+            }
+
+            while ([commandBatch count] > 0) {
+                @autoreleasepool {
+                    // Execute the commands one-at-a-time.
+                    NSArray* jsonEntry = [commandBatch cdv_dequeue];
+                    if ([commandBatch count] == 0) {
+                        [_queue removeObjectAtIndex:0];
+                    }
+                    CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
+                    CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName);
+
+                    if (![self execute:command]) {
+#ifdef DEBUG
+                            NSString* commandJson = [jsonEntry cdv_JSONString];
+                            static NSUInteger maxLogLength = 1024;
+                            NSString* commandString = ([commandJson length] > maxLogLength) ?
+                                [NSString stringWithFormat : @"%@[...]", [commandJson substringToIndex:maxLogLength]] :
+                                commandJson;
+
+                            DLog(@"FAILED pluginJSON = %@", commandString);
+#endif
+                    }
+                }
+
+                // Yield if we're taking too long.
+                if (([_queue count] > 0) && ([NSDate timeIntervalSinceReferenceDate] - _startExecutionTime > MAX_EXECUTION_TIME)) {
+                    [self performSelector:@selector(executePending) withObject:nil afterDelay:0];
+                    return;
+                }
+            }
+        }
+    } @finally
+    {
+        _startExecutionTime = 0;
+    }
+}
+
+- (BOOL)execute:(CDVInvokedUrlCommand*)command
+{
+    if ((command.className == nil) || (command.methodName == nil)) {
+        NSLog(@"ERROR: Classname and/or methodName not found for command.");
+        return NO;
+    }
+
+    // Fetch an instance of this class
+    CDVPlugin* obj = [_viewController.commandDelegate getCommandInstance:command.className];
+
+    if (!([obj isKindOfClass:[CDVPlugin class]])) {
+        NSLog(@"ERROR: Plugin '%@' not found, or is not a CDVPlugin. Check your plugin mapping in config.xml.", command.className);
+        return NO;
+    }
+    BOOL retVal = YES;
+    double started = [[NSDate date] timeIntervalSince1970] * 1000.0;
+    // Find the proper selector to call.
+    NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName];
+    SEL normalSelector = NSSelectorFromString(methodName);
+    if ([obj respondsToSelector:normalSelector]) {
+        // [obj performSelector:normalSelector withObject:command];
+        ((void (*)(id, SEL, id))objc_msgSend)(obj, normalSelector, command);
+    } else {
+        // There's no method to call, so throw an error.
+        NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className);
+        retVal = NO;
+    }
+    double elapsed = [[NSDate date] timeIntervalSince1970] * 1000.0 - started;
+    if (elapsed > 10) {
+        NSLog(@"THREAD WARNING: ['%@'] took '%f' ms. Plugin should use a background thread.", command.className, elapsed);
+    }
+    return retVal;
+}
+
+@end

+ 30 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVConfigParser.h

@@ -0,0 +1,30 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+@interface CDVConfigParser : NSObject <NSXMLParserDelegate>
+{
+    NSString* featureName;
+}
+
+@property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict;
+@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
+@property (nonatomic, readonly, strong) NSMutableArray* startupPluginNames;
+@property (nonatomic, readonly, strong) NSString* startPage;
+
+@end

+ 81 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVConfigParser.m

@@ -0,0 +1,81 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVConfigParser.h"
+
+@interface CDVConfigParser ()
+
+@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict;
+@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
+@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
+@property (nonatomic, readwrite, strong) NSString* startPage;
+
+@end
+
+@implementation CDVConfigParser
+
+@synthesize pluginsDict, settings, startPage, startupPluginNames;
+
+- (id)init
+{
+    self = [super init];
+    if (self != nil) {
+        self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30];
+        self.settings = [[NSMutableDictionary alloc] initWithCapacity:30];
+        self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8];
+        featureName = nil;
+    }
+    return self;
+}
+
+- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict
+{
+    if ([elementName isEqualToString:@"preference"]) {
+        settings[[attributeDict[@"name"] lowercaseString]] = attributeDict[@"value"];
+    } else if ([elementName isEqualToString:@"feature"]) { // store feature name to use with correct parameter set
+        featureName = [attributeDict[@"name"] lowercaseString];
+    } else if ((featureName != nil) && [elementName isEqualToString:@"param"]) {
+        NSString* paramName = [attributeDict[@"name"] lowercaseString];
+        id value = attributeDict[@"value"];
+        if ([paramName isEqualToString:@"ios-package"]) {
+            pluginsDict[featureName] = value;
+        }
+        BOOL paramIsOnload = ([paramName isEqualToString:@"onload"] && [@"true" isEqualToString : value]);
+        BOOL attribIsOnload = [@"true" isEqualToString :[attributeDict[@"onload"] lowercaseString]];
+        if (paramIsOnload || attribIsOnload) {
+            [self.startupPluginNames addObject:featureName];
+        }
+    } else if ([elementName isEqualToString:@"content"]) {
+        self.startPage = attributeDict[@"src"];
+    }
+}
+
+- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName
+{
+    if ([elementName isEqualToString:@"feature"]) { // no longer handling a feature so release
+        featureName = nil;
+    }
+}
+
+- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError
+{
+    NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]);
+}
+
+@end

+ 52 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVInvokedUrlCommand.h

@@ -0,0 +1,52 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface CDVInvokedUrlCommand : NSObject {
+    NSString* _callbackId;
+    NSString* _className;
+    NSString* _methodName;
+    NSArray* _arguments;
+}
+
+@property (nonatomic, readonly) NSArray* arguments;
+@property (nonatomic, readonly) NSString* callbackId;
+@property (nonatomic, readonly) NSString* className;
+@property (nonatomic, readonly) NSString* methodName;
+
++ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry;
+
+- (id)initWithArguments:(NSArray*)arguments
+             callbackId:(NSString*)callbackId
+              className:(NSString*)className
+             methodName:(NSString*)methodName;
+
+- (id)initFromJson:(NSArray*)jsonEntry;
+
+// Returns the argument at the given index.
+// If index >= the number of arguments, returns nil.
+// If the argument at the given index is NSNull, returns nil.
+- (id)argumentAtIndex:(NSUInteger)index;
+// Same as above, but returns defaultValue instead of nil.
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue;
+// Same as above, but returns defaultValue instead of nil, and if the argument is not of the expected class, returns defaultValue
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass;
+
+@end

+ 116 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVInvokedUrlCommand.m

@@ -0,0 +1,116 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVInvokedUrlCommand.h"
+#import "CDVJSON_private.h"
+
+@implementation CDVInvokedUrlCommand
+
+@synthesize arguments = _arguments;
+@synthesize callbackId = _callbackId;
+@synthesize className = _className;
+@synthesize methodName = _methodName;
+
++ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry
+{
+    return [[CDVInvokedUrlCommand alloc] initFromJson:jsonEntry];
+}
+
+- (id)initFromJson:(NSArray*)jsonEntry
+{
+    id tmp = [jsonEntry objectAtIndex:0];
+    NSString* callbackId = tmp == [NSNull null] ? nil : tmp;
+    NSString* className = [jsonEntry objectAtIndex:1];
+    NSString* methodName = [jsonEntry objectAtIndex:2];
+    NSMutableArray* arguments = [jsonEntry objectAtIndex:3];
+
+    return [self initWithArguments:arguments
+                        callbackId:callbackId
+                         className:className
+                        methodName:methodName];
+}
+
+- (id)initWithArguments:(NSArray*)arguments
+             callbackId:(NSString*)callbackId
+              className:(NSString*)className
+             methodName:(NSString*)methodName
+{
+    self = [super init];
+    if (self != nil) {
+        _arguments = arguments;
+        _callbackId = callbackId;
+        _className = className;
+        _methodName = methodName;
+    }
+    [self massageArguments];
+    return self;
+}
+
+- (void)massageArguments
+{
+    NSMutableArray* newArgs = nil;
+
+    for (NSUInteger i = 0, count = [_arguments count]; i < count; ++i) {
+        id arg = [_arguments objectAtIndex:i];
+        if (![arg isKindOfClass:[NSDictionary class]]) {
+            continue;
+        }
+        NSDictionary* dict = arg;
+        NSString* type = [dict objectForKey:@"CDVType"];
+        if (!type || ![type isEqualToString:@"ArrayBuffer"]) {
+            continue;
+        }
+        NSString* data = [dict objectForKey:@"data"];
+        if (!data) {
+            continue;
+        }
+        if (newArgs == nil) {
+            newArgs = [NSMutableArray arrayWithArray:_arguments];
+            _arguments = newArgs;
+        }
+        [newArgs replaceObjectAtIndex:i withObject:[[NSData alloc] initWithBase64EncodedString:data options:0]];
+    }
+}
+
+- (id)argumentAtIndex:(NSUInteger)index
+{
+    return [self argumentAtIndex:index withDefault:nil];
+}
+
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue
+{
+    return [self argumentAtIndex:index withDefault:defaultValue andClass:nil];
+}
+
+- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass
+{
+    if (index >= [_arguments count]) {
+        return defaultValue;
+    }
+    id ret = [_arguments objectAtIndex:index];
+    if (ret == [NSNull null]) {
+        ret = defaultValue;
+    }
+    if ((aClass != nil) && ![ret isKindOfClass:aClass]) {
+        ret = defaultValue;
+    }
+    return ret;
+}
+
+@end

+ 39 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin+Resources.h

@@ -0,0 +1,39 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import "CDVPlugin.h"
+
+@interface CDVPlugin (CDVPluginResources)
+
+/*
+ This will return the localized string for a key in a .bundle that is named the same as your class
+ For example, if your plugin class was called Foo, and you have a Spanish localized strings file, it will
+ try to load the desired key from Foo.bundle/es.lproj/Localizable.strings
+ */
+- (NSString*)pluginLocalizedString:(NSString*)key;
+
+/*
+ This will return the image for a name in a .bundle that is named the same as your class
+ For example, if your plugin class was called Foo, and you have an image called "bar",
+ it will try to load the image from Foo.bundle/bar.png (and appropriately named retina versions)
+ */
+- (UIImage*)pluginImageResource:(NSString*)name;
+
+@end

+ 38 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin+Resources.m

@@ -0,0 +1,38 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPlugin+Resources.h"
+
+@implementation CDVPlugin (CDVPluginResources)
+
+- (NSString*)pluginLocalizedString:(NSString*)key
+{
+    NSBundle* bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:NSStringFromClass([self class]) ofType:@"bundle"]];
+
+    return [bundle localizedStringForKey:(key) value:nil table:nil];
+}
+
+- (UIImage*)pluginImageResource:(NSString*)name
+{
+    NSString* resourceIdentifier = [NSString stringWithFormat:@"%@.bundle/%@", NSStringFromClass([self class]), name];
+
+    return [UIImage imageNamed:resourceIdentifier];
+}
+
+@end

+ 74 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin.h

@@ -0,0 +1,74 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import "CDVPluginResult.h"
+#import "NSMutableArray+QueueAdditions.h"
+#import "CDVCommandDelegate.h"
+#import "CDVWebViewEngineProtocol.h"
+
+@interface UIView (org_apache_cordova_UIView_Extension)
+
+@property (nonatomic, weak) UIScrollView* scrollView;
+
+@end
+
+extern NSString* const CDVPageDidLoadNotification;
+extern NSString* const CDVPluginHandleOpenURLNotification;
+extern NSString* const CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification;
+extern NSString* const CDVPluginResetNotification;
+extern NSString* const CDVViewWillAppearNotification;
+extern NSString* const CDVViewDidAppearNotification;
+extern NSString* const CDVViewWillDisappearNotification;
+extern NSString* const CDVViewDidDisappearNotification;
+extern NSString* const CDVViewWillLayoutSubviewsNotification;
+extern NSString* const CDVViewDidLayoutSubviewsNotification;
+extern NSString* const CDVViewWillTransitionToSizeNotification;
+
+@interface CDVPlugin : NSObject {}
+
+@property (nonatomic, readonly, weak) UIView* webView;
+@property (nonatomic, readonly, weak) id <CDVWebViewEngineProtocol> webViewEngine;
+
+@property (nonatomic, weak) UIViewController* viewController;
+@property (nonatomic, weak) id <CDVCommandDelegate> commandDelegate;
+
+@property (readonly, assign) BOOL hasPendingOperation;
+
+- (void)pluginInitialize;
+
+- (void)handleOpenURL:(NSNotification*)notification;
+- (void)handleOpenURLWithApplicationSourceAndAnnotation:(NSNotification*)notification;
+- (void)onAppTerminate;
+- (void)onMemoryWarning;
+- (void)onReset;
+- (void)dispose;
+
+/*
+ // see initWithWebView implementation
+ - (void) onPause {}
+ - (void) onResume {}
+ - (void) onOrientationWillChange {}
+ - (void) onOrientationDidChange {}
+ */
+
+- (id)appDelegate;
+
+@end

+ 199 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVPlugin.m

@@ -0,0 +1,199 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPlugin.h"
+#import "CDVPlugin+Private.h"
+#import "CDVPlugin+Resources.h"
+#import "CDVViewController.h"
+#include <objc/message.h>
+
+@implementation UIView (org_apache_cordova_UIView_Extension)
+
+@dynamic scrollView;
+
+- (UIScrollView*)scrollView
+{
+    SEL scrollViewSelector = NSSelectorFromString(@"scrollView");
+
+    if ([self respondsToSelector:scrollViewSelector]) {
+        return ((id (*)(id, SEL))objc_msgSend)(self, scrollViewSelector);
+    }
+
+    return nil;
+}
+
+@end
+
+NSString* const CDVPageDidLoadNotification = @"CDVPageDidLoadNotification";
+NSString* const CDVPluginHandleOpenURLNotification = @"CDVPluginHandleOpenURLNotification";
+NSString* const CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification = @"CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification";
+NSString* const CDVPluginResetNotification = @"CDVPluginResetNotification";
+NSString* const CDVViewWillAppearNotification = @"CDVViewWillAppearNotification";
+NSString* const CDVViewDidAppearNotification = @"CDVViewDidAppearNotification";
+NSString* const CDVViewWillDisappearNotification = @"CDVViewWillDisappearNotification";
+NSString* const CDVViewDidDisappearNotification = @"CDVViewDidDisappearNotification";
+NSString* const CDVViewWillLayoutSubviewsNotification = @"CDVViewWillLayoutSubviewsNotification";
+NSString* const CDVViewDidLayoutSubviewsNotification = @"CDVViewDidLayoutSubviewsNotification";
+NSString* const CDVViewWillTransitionToSizeNotification = @"CDVViewWillTransitionToSizeNotification";
+
+@interface CDVPlugin ()
+
+@property (readwrite, assign) BOOL hasPendingOperation;
+@property (nonatomic, readwrite, weak) id <CDVWebViewEngineProtocol> webViewEngine;
+
+@end
+
+@implementation CDVPlugin
+@synthesize webViewEngine, viewController, commandDelegate, hasPendingOperation;
+@dynamic webView;
+
+// Do not override these methods. Use pluginInitialize instead.
+- (instancetype)initWithWebViewEngine:(id <CDVWebViewEngineProtocol>)theWebViewEngine
+{
+    self = [super init];
+    if (self) {
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppTerminate) name:UIApplicationWillTerminateNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURLWithApplicationSourceAndAnnotation:) name:CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:theWebViewEngine.engineWebView];
+
+        self.webViewEngine = theWebViewEngine;
+    }
+    return self;
+}
+
+- (void)pluginInitialize
+{
+    // You can listen to more app notifications, see:
+    // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4
+
+    // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler
+
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
+
+    // Added in 2.5.0
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:self.webView];
+    //Added in 4.3.0
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillAppear:) name:CDVViewWillAppearNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidAppear:) name:CDVViewDidAppearNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillDisappear:) name:CDVViewWillDisappearNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidDisappear:) name:CDVViewDidDisappearNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillLayoutSubviews:) name:CDVViewWillLayoutSubviewsNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidLayoutSubviews:) name:CDVViewDidLayoutSubviewsNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillTransitionToSize:) name:CDVViewWillTransitionToSizeNotification object:nil];
+}
+
+- (void)dispose
+{
+    viewController = nil;
+    commandDelegate = nil;
+}
+
+- (UIView*)webView
+{
+    if (self.webViewEngine != nil) {
+        return self.webViewEngine.engineWebView;
+    }
+
+    return nil;
+}
+
+/*
+// NOTE: for onPause and onResume, calls into JavaScript must not call or trigger any blocking UI, like alerts
+- (void) onPause {}
+- (void) onResume {}
+- (void) onOrientationWillChange {}
+- (void) onOrientationDidChange {}
+*/
+
+/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */
+- (void)handleOpenURL:(NSNotification*)notification
+{
+    // override to handle urls sent to your app
+    // register your url schemes in your App-Info.plist
+
+    NSURL* url = [notification object];
+
+    if ([url isKindOfClass:[NSURL class]]) {
+        /* Do your thing! */
+    }
+}
+
+/*
+    NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts
+ */
+- (void)handleOpenURLWithApplicationSourceAndAnnotation: (NSNotification*)notification
+{
+    
+    // override to handle urls sent to your app
+    // register your url schemes in your App-Info.plist
+    
+    // The notification object is an NSDictionary which contains
+    // - url which is a type of NSURL
+    // - sourceApplication which is a type of NSString and represents the package
+    // id of the app that calls our app
+    // - annotation which a type of Property list which can be several different types
+    // please see https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/PropertyList.html
+    
+    NSDictionary*  notificationData = [notification object];
+    
+    if ([notificationData isKindOfClass: NSDictionary.class]){
+        
+        NSURL* url = notificationData[@"url"];
+        NSString* sourceApplication = notificationData[@"sourceApplication"];
+        id annotation = notificationData[@"annotation"];
+        
+        if ([url isKindOfClass:NSURL.class] && [sourceApplication isKindOfClass:NSString.class] && annotation) {
+            /* Do your thing! */
+        }
+    }
+}
+
+
+/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */
+- (void)onAppTerminate
+{
+    // override this if you need to do any cleanup on app exit
+}
+
+- (void)onMemoryWarning
+{
+    // override to remove caches, etc
+}
+
+- (void)onReset
+{
+    // Override to cancel any long-running requests when the WebView navigates or refreshes.
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];   // this will remove all notifications unless added using addObserverForName:object:queue:usingBlock:
+}
+
+- (id)appDelegate
+{
+    return [[UIApplication sharedApplication] delegate];
+}
+
+@end

+ 83 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVPluginResult.h

@@ -0,0 +1,83 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import "CDVAvailability.h"
+
+typedef NS_ENUM(NSUInteger, CDVCommandStatus) {
+    CDVCommandStatus_NO_RESULT NS_SWIFT_NAME(noResult) = 0,
+    CDVCommandStatus_OK NS_SWIFT_NAME(ok),
+    CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION NS_SWIFT_NAME(classNotFoundException),
+    CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION NS_SWIFT_NAME(illegalAccessException),
+    CDVCommandStatus_INSTANTIATION_EXCEPTION NS_SWIFT_NAME(instantiationException),
+    CDVCommandStatus_MALFORMED_URL_EXCEPTION NS_SWIFT_NAME(malformedUrlException),
+    CDVCommandStatus_IO_EXCEPTION NS_SWIFT_NAME(ioException),
+    CDVCommandStatus_INVALID_ACTION NS_SWIFT_NAME(invalidAction),
+    CDVCommandStatus_JSON_EXCEPTION NS_SWIFT_NAME(jsonException),
+    CDVCommandStatus_ERROR NS_SWIFT_NAME(error)
+};
+
+// This exists to preserve compatibility with early Swift plugins, who are
+// using CDVCommandStatus as ObjC-style constants rather than as Swift enum
+// values.
+// This declares extern'ed constants (implemented in CDVPluginResult.m)
+#define SWIFT_ENUM_COMPAT_HACK(enumVal) extern const CDVCommandStatus SWIFT_##enumVal NS_SWIFT_NAME(enumVal)
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_NO_RESULT);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_OK);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INSTANTIATION_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_MALFORMED_URL_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_IO_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INVALID_ACTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_JSON_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ERROR);
+#undef SWIFT_ENUM_COMPAT_HACK
+
+@interface CDVPluginResult : NSObject {}
+
+@property (nonatomic, strong, readonly) NSNumber* status;
+@property (nonatomic, strong, readonly) id message;
+@property (nonatomic, strong)           NSNumber* keepCallback;
+// This property can be used to scope the lifetime of another object. For example,
+// Use it to store the associated NSData when `message` is created using initWithBytesNoCopy.
+@property (nonatomic, strong) id associatedObject;
+
+- (CDVPluginResult*)init;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSInteger:(NSInteger)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSUInteger:(NSUInteger)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode;
+
++ (void)setVerbose:(BOOL)verbose;
++ (BOOL)isVerbose;
+
+- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback;
+
+- (NSString*)argumentsAsJSON;
+
+@end

+ 203 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVPluginResult.m

@@ -0,0 +1,203 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVPluginResult.h"
+#import "CDVJSON_private.h"
+#import "CDVDebug.h"
+
+// This exists to preserve compatibility with early Swift plugins, who are
+// using CDVCommandStatus as ObjC-style constants rather than as Swift enum
+// values.
+// These constants alias the enum values back to their previous names.
+#define SWIFT_ENUM_COMPAT_HACK(enumVal) const CDVCommandStatus SWIFT_##enumVal NS_SWIFT_NAME(enumVal) = enumVal
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_NO_RESULT);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_OK);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INSTANTIATION_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_MALFORMED_URL_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_IO_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_INVALID_ACTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_JSON_EXCEPTION);
+SWIFT_ENUM_COMPAT_HACK(CDVCommandStatus_ERROR);
+#undef SWIFT_ENUM_COMPAT_HACK
+
+@interface CDVPluginResult ()
+
+- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage;
+
+@end
+
+@implementation CDVPluginResult
+@synthesize status, message, keepCallback, associatedObject;
+
+static NSArray* org_apache_cordova_CommandStatusMsgs;
+
+id messageFromArrayBuffer(NSData* data)
+{
+    return @{
+               @"CDVType" : @"ArrayBuffer",
+               @"data" :[data base64EncodedStringWithOptions:0]
+    };
+}
+
+id massageMessage(id message)
+{
+    if ([message isKindOfClass:[NSData class]]) {
+        return messageFromArrayBuffer(message);
+    }
+    return message;
+}
+
+id messageFromMultipart(NSArray* theMessages)
+{
+    NSMutableArray* messages = [NSMutableArray arrayWithArray:theMessages];
+
+    for (NSUInteger i = 0; i < messages.count; ++i) {
+        [messages replaceObjectAtIndex:i withObject:massageMessage([messages objectAtIndex:i])];
+    }
+
+    return @{
+               @"CDVType" : @"MultiPart",
+               @"messages" : messages
+    };
+}
+
++ (void)initialize
+{
+    org_apache_cordova_CommandStatusMsgs = [[NSArray alloc] initWithObjects:@"No result",
+        @"OK",
+        @"Class not found",
+        @"Illegal access",
+        @"Instantiation error",
+        @"Malformed url",
+        @"IO error",
+        @"Invalid action",
+        @"JSON error",
+        @"Error",
+        nil];
+}
+
+- (CDVPluginResult*)init
+{
+    return [self initWithStatus:CDVCommandStatus_NO_RESULT message:nil];
+}
+
+- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage
+{
+    self = [super init];
+    if (self) {
+        status = @(statusOrdinal);
+        message = theMessage;
+        keepCallback = [NSNumber numberWithBool:NO];
+    }
+    return self;
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:nil];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:theMessage];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:theMessage];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithInt:theMessage]];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSInteger:(NSInteger)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithInteger:theMessage]];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSUInteger:(NSUInteger)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithUnsignedInteger:theMessage]];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithDouble:theMessage]];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithBool:theMessage]];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:theMessage];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:messageFromArrayBuffer(theMessage)];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:messageFromMultipart(theMessages)];
+}
+
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode
+{
+    NSDictionary* errDict = @{@"code" :[NSNumber numberWithInt:errorCode]};
+
+    return [[self alloc] initWithStatus:statusOrdinal message:errDict];
+}
+
+- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback
+{
+    [self setKeepCallback:[NSNumber numberWithBool:bKeepCallback]];
+}
+
+- (NSString*)argumentsAsJSON
+{
+    id arguments = (self.message == nil ? [NSNull null] : self.message);
+    NSArray* argumentsWrappedInArray = [NSArray arrayWithObject:arguments];
+
+    NSString* argumentsJSON = [argumentsWrappedInArray cdv_JSONString];
+
+    argumentsJSON = [argumentsJSON substringWithRange:NSMakeRange(1, [argumentsJSON length] - 2)];
+
+    return argumentsJSON;
+}
+
+static BOOL gIsVerbose = NO;
++ (void)setVerbose:(BOOL)verbose
+{
+    gIsVerbose = verbose;
+}
+
++ (BOOL)isVerbose
+{
+    return gIsVerbose;
+}
+
+@end

+ 28 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVScreenOrientationDelegate.h

@@ -0,0 +1,28 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@protocol CDVScreenOrientationDelegate <NSObject>
+
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations;
+
+- (BOOL)shouldAutorotate;
+
+@end

+ 27 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVTimer.h

@@ -0,0 +1,27 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface CDVTimer : NSObject
+
++ (void)start:(NSString*)name;
++ (void)stop:(NSString*)name;
+
+@end

+ 123 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVTimer.m

@@ -0,0 +1,123 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVTimer.h"
+
+#pragma mark CDVTimerItem
+
+@interface CDVTimerItem : NSObject
+
+@property (nonatomic, strong) NSString* name;
+@property (nonatomic, strong) NSDate* started;
+@property (nonatomic, strong) NSDate* ended;
+
+- (void)log;
+
+@end
+
+@implementation CDVTimerItem
+
+- (void)log
+{
+    NSLog(@"[CDVTimer][%@] %fms", self.name, [self.ended timeIntervalSinceDate:self.started] * 1000.0);
+}
+
+@end
+
+#pragma mark CDVTimer
+
+@interface CDVTimer ()
+
+@property (nonatomic, strong) NSMutableDictionary* items;
+
+@end
+
+@implementation CDVTimer
+
+#pragma mark object methods
+
+- (id)init
+{
+    if (self = [super init]) {
+        self.items = [NSMutableDictionary dictionaryWithCapacity:6];
+    }
+
+    return self;
+}
+
+- (void)add:(NSString*)name
+{
+    if ([self.items objectForKey:[name lowercaseString]] == nil) {
+        CDVTimerItem* item = [CDVTimerItem new];
+        item.name = name;
+        item.started = [NSDate new];
+        [self.items setObject:item forKey:[name lowercaseString]];
+    } else {
+        NSLog(@"Timer called '%@' already exists.", name);
+    }
+}
+
+- (void)remove:(NSString*)name
+{
+    CDVTimerItem* item = [self.items objectForKey:[name lowercaseString]];
+
+    if (item != nil) {
+        item.ended = [NSDate new];
+        [item log];
+        [self.items removeObjectForKey:[name lowercaseString]];
+    } else {
+        NSLog(@"Timer called '%@' does not exist.", name);
+    }
+}
+
+- (void)removeAll
+{
+    [self.items removeAllObjects];
+}
+
+#pragma mark class methods
+
++ (void)start:(NSString*)name
+{
+    [[CDVTimer sharedInstance] add:name];
+}
+
++ (void)stop:(NSString*)name
+{
+    [[CDVTimer sharedInstance] remove:name];
+}
+
++ (void)clearAll
+{
+    [[CDVTimer sharedInstance] removeAll];
+}
+
++ (CDVTimer*)sharedInstance
+{
+    static dispatch_once_t pred = 0;
+    __strong static CDVTimer* _sharedObject = nil;
+
+    dispatch_once(&pred, ^{
+            _sharedObject = [[self alloc] init];
+        });
+
+    return _sharedObject;
+}
+
+@end

+ 32 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVURLSchemeHandler.h

@@ -0,0 +1,32 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WebKit/WebKit.h>
+#import "CDVViewController.h"
+
+
+@interface CDVURLSchemeHandler : NSObject <WKURLSchemeHandler>
+
+@property (nonatomic, strong) CDVViewController* viewController;
+
+- (instancetype)initWithVC:(CDVViewController *)controller;
+
+
+@end

+ 108 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVURLSchemeHandler.m

@@ -0,0 +1,108 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+
+#import "CDVURLSchemeHandler.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+
+@implementation CDVURLSchemeHandler
+
+
+- (instancetype)initWithVC:(CDVViewController *)controller
+{
+    self = [super init];
+    if (self) {
+        _viewController = controller;
+    }
+    return self;
+}
+
+- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
+{
+    NSString * startPath = [[NSBundle mainBundle] pathForResource:self.viewController.wwwFolderName ofType: nil];
+    NSURL * url = urlSchemeTask.request.URL;
+    NSString * stringToLoad = url.path;
+    NSString * scheme = url.scheme;
+
+    if ([scheme isEqualToString:self.viewController.appScheme]) {
+        if ([stringToLoad hasPrefix:@"/_app_file_"]) {
+            startPath = [stringToLoad stringByReplacingOccurrencesOfString:@"/_app_file_" withString:@""];
+        } else {
+            if ([stringToLoad isEqualToString:@""] || [url.pathExtension isEqualToString:@""]) {
+                startPath = [startPath stringByAppendingPathComponent:self.viewController.startPage];
+            } else {
+                startPath = [startPath stringByAppendingPathComponent:stringToLoad];
+            }
+        }
+    }
+
+    NSError * fileError = nil;
+    NSData * data = nil;
+    if ([self isMediaExtension:url.pathExtension]) {
+        data = [NSData dataWithContentsOfFile:startPath options:NSDataReadingMappedIfSafe error:&fileError];
+    }
+    if (!data || fileError) {
+        data =  [[NSData alloc] initWithContentsOfFile:startPath];
+    }
+    NSInteger statusCode = 200;
+    if (!data) {
+        statusCode = 404;
+    }
+    NSURL * localUrl = [NSURL URLWithString:url.absoluteString];
+    NSString * mimeType = [self getMimeType:url.pathExtension];
+    id response = nil;
+    if (data && [self isMediaExtension:url.pathExtension]) {
+        response = [[NSURLResponse alloc] initWithURL:localUrl MIMEType:mimeType expectedContentLength:data.length textEncodingName:nil];
+    } else {
+        NSDictionary * headers = @{ @"Content-Type" : mimeType, @"Cache-Control": @"no-cache"};
+        response = [[NSHTTPURLResponse alloc] initWithURL:localUrl statusCode:statusCode HTTPVersion:nil headerFields:headers];
+    }
+
+    [urlSchemeTask didReceiveResponse:response];
+    [urlSchemeTask didReceiveData:data];
+    [urlSchemeTask didFinish];
+
+}
+
+- (void)webView:(nonnull WKWebView *)webView stopURLSchemeTask:(nonnull id<WKURLSchemeTask>)urlSchemeTask
+{
+
+}
+
+-(NSString *) getMimeType:(NSString *)fileExtension {
+    if (fileExtension && ![fileExtension isEqualToString:@""]) {
+        NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL);
+        NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
+        return contentType ? contentType : @"application/octet-stream";
+    } else {
+        return @"text/html";
+    }
+}
+
+-(BOOL) isMediaExtension:(NSString *) pathExtension {
+    NSArray * mediaExtensions = @[@"m4v", @"mov", @"mp4",
+                           @"aac", @"ac3", @"aiff", @"au", @"flac", @"m4a", @"mp3", @"wav"];
+    if ([mediaExtensions containsObject:pathExtension.lowercaseString]) {
+        return YES;
+    }
+    return NO;
+}
+
+
+@end

+ 77 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVViewController.h

@@ -0,0 +1,77 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <Foundation/NSJSONSerialization.h>
+#import "CDVAvailability.h"
+#import "CDVInvokedUrlCommand.h"
+#import "CDVCommandDelegate.h"
+#import "CDVCommandQueue.h"
+#import "CDVScreenOrientationDelegate.h"
+#import "CDVPlugin.h"
+#import "CDVWebViewEngineProtocol.h"
+
+@interface CDVViewController : UIViewController <CDVScreenOrientationDelegate>{
+    @protected
+    id <CDVWebViewEngineProtocol> _webViewEngine;
+    @protected
+    id <CDVCommandDelegate> _commandDelegate;
+    @protected
+    CDVCommandQueue* _commandQueue;
+}
+
+@property (nonatomic, readonly, weak) IBOutlet UIView* webView;
+
+@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
+@property (nonatomic, readonly, strong) NSDictionary* pluginsMap;
+@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
+@property (nonatomic, readonly, strong) NSXMLParser* configParser;
+
+@property (nonatomic, readwrite, copy) NSString* appScheme;
+@property (nonatomic, readwrite, copy) NSString* configFile;
+@property (nonatomic, readwrite, copy) NSString* wwwFolderName;
+@property (nonatomic, readwrite, copy) NSString* startPage;
+@property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue;
+@property (nonatomic, readonly, strong) id <CDVWebViewEngineProtocol> webViewEngine;
+@property (nonatomic, readonly, strong) id <CDVCommandDelegate> commandDelegate;
+
+/**
+	Takes/Gives an array of UIInterfaceOrientation (int) objects
+	ex. UIInterfaceOrientationPortrait
+*/
+@property (nonatomic, readwrite, strong) NSArray* supportedOrientations;
+
+- (UIView*)newCordovaViewWithFrame:(CGRect)bounds;
+
+- (NSString*)appURLScheme;
+- (NSURL*)errorURL;
+
+- (UIColor*)colorFromColorString:(NSString*)colorString CDV_DEPRECATED(7.0.0, "Use BackgroundColor in xcassets");
+- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations;
+- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation;
+
+- (id)getCommandInstance:(NSString*)pluginName;
+- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className;
+- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName;
+
+- (void)parseSettingsWithParser:(NSObject <NSXMLParserDelegate>*)delegate;
+
+- (void)showLaunchScreen:(BOOL)visible;
+
+@end

+ 813 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVViewController.m

@@ -0,0 +1,813 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <objc/message.h>
+#import "CDV.h"
+#import "CDVPlugin+Private.h"
+#import "CDVWebViewUIDelegate.h"
+#import "CDVConfigParser.h"
+#import <AVFoundation/AVFoundation.h>
+#import "NSDictionary+CordovaPreferences.h"
+#import "CDVCommandDelegateImpl.h"
+#import <Foundation/NSCharacterSet.h>
+
+@interface CDVViewController () { }
+
+@property (nonatomic, readwrite, strong) NSXMLParser* configParser;
+@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
+@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
+@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
+@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;
+@property (nonatomic, readwrite, strong) id <CDVWebViewEngineProtocol> webViewEngine;
+@property (nonatomic, readwrite, strong) UIView* launchView;
+
+@property (readwrite, assign) BOOL initialized;
+
+@property (atomic, strong) NSURL* openURL;
+
+@end
+
+@implementation CDVViewController
+
+@synthesize supportedOrientations;
+@synthesize pluginObjects, pluginsMap, startupPluginNames;
+@synthesize configParser, settings;
+@synthesize wwwFolderName, startPage, initialized, openURL;
+@synthesize commandDelegate = _commandDelegate;
+@synthesize commandQueue = _commandQueue;
+@synthesize webViewEngine = _webViewEngine;
+@dynamic webView;
+
+- (void)__init
+{
+    if ((self != nil) && !self.initialized) {
+        _commandQueue = [[CDVCommandQueue alloc] initWithViewController:self];
+        _commandDelegate = [[CDVCommandDelegateImpl alloc] initWithViewController:self];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillTerminate:)
+                                                     name:UIApplicationWillTerminateNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillResignActive:)
+                                                     name:UIApplicationWillResignActiveNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidBecomeActive:)
+                                                     name:UIApplicationDidBecomeActiveNotification object:nil];
+
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:)
+                                                     name:UIApplicationWillEnterForegroundNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:)
+                                                     name:UIApplicationDidEnterBackgroundNotification object:nil];
+
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onWebViewPageDidLoad:)
+                                                     name:CDVPageDidLoadNotification object:nil];
+
+        // read from UISupportedInterfaceOrientations (or UISupportedInterfaceOrientations~iPad, if its iPad) from -Info.plist
+        self.supportedOrientations = [self parseInterfaceOrientations:
+            [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]];
+
+        [self printVersion];
+        [self printMultitaskingInfo];
+        [self printPlatformVersionWarning];
+        self.initialized = YES;
+    }
+}
+
+- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
+{
+    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+    [self __init];
+    return self;
+}
+
+- (id)initWithCoder:(NSCoder*)aDecoder
+{
+    self = [super initWithCoder:aDecoder];
+    [self __init];
+    return self;
+}
+
+- (id)init
+{
+    self = [super init];
+    [self __init];
+    return self;
+}
+
+- (void)printVersion
+{
+    NSLog(@"Apache Cordova native platform version %@ is starting.", CDV_VERSION);
+}
+
+- (void)printPlatformVersionWarning
+{
+    if (!IsAtLeastiOSVersion(@"8.0")) {
+        NSLog(@"CRITICAL: For Cordova 4.0.0 and above, you will need to upgrade to at least iOS 8.0 or greater. Your current version of iOS is %@.",
+            [[UIDevice currentDevice] systemVersion]
+            );
+    }
+}
+
+- (void)printMultitaskingInfo
+{
+    UIDevice* device = [UIDevice currentDevice];
+    BOOL backgroundSupported = NO;
+
+    if ([device respondsToSelector:@selector(isMultitaskingSupported)]) {
+        backgroundSupported = device.multitaskingSupported;
+    }
+
+    NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"];
+    if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default)
+        exitsOnSuspend = [NSNumber numberWithBool:NO];
+    }
+
+    NSLog(@"Multi-tasking -> Device: %@, App: %@", (backgroundSupported ? @"YES" : @"NO"), (![exitsOnSuspend intValue]) ? @"YES" : @"NO");
+}
+
+-(NSString*)configFilePath{
+    NSString* path = self.configFile ?: @"config.xml";
+
+    // if path is relative, resolve it against the main bundle
+    if(![path isAbsolutePath]){
+        NSString* absolutePath = [[NSBundle mainBundle] pathForResource:path ofType:nil];
+        if(!absolutePath){
+            NSAssert(NO, @"ERROR: %@ not found in the main bundle!", path);
+        }
+        path = absolutePath;
+    }
+
+    // Assert file exists
+    if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
+        NSAssert(NO, @"ERROR: %@ does not exist. Please run cordova-ios/bin/cordova_plist_to_config_xml path/to/project.", path);
+        return nil;
+    }
+
+    return path;
+}
+
+- (void)parseSettingsWithParser:(NSObject <NSXMLParserDelegate>*)delegate
+{
+    // read from config.xml in the app bundle
+    NSString* path = [self configFilePath];
+
+    NSURL* url = [NSURL fileURLWithPath:path];
+
+    self.configParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
+    if (self.configParser == nil) {
+        NSLog(@"Failed to initialize XML parser.");
+        return;
+    }
+    [self.configParser setDelegate:((id < NSXMLParserDelegate >)delegate)];
+    [self.configParser parse];
+}
+
+- (void)loadSettings
+{
+    CDVConfigParser* delegate = [[CDVConfigParser alloc] init];
+
+    [self parseSettingsWithParser:delegate];
+
+    // Get the plugin dictionary, whitelist and settings from the delegate.
+    self.pluginsMap = delegate.pluginsDict;
+    self.startupPluginNames = delegate.startupPluginNames;
+    self.settings = delegate.settings;
+
+    // And the start folder/page.
+    if(self.wwwFolderName == nil){
+        self.wwwFolderName = @"www";
+    }
+    if(delegate.startPage && self.startPage == nil){
+        self.startPage = delegate.startPage;
+    }
+    if (self.startPage == nil) {
+        self.startPage = @"index.html";
+    }
+
+    // Initialize the plugin objects dict.
+    self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20];
+}
+
+- (NSURL*)appUrl
+{
+    NSURL* appURL = nil;
+
+    if ([self.startPage rangeOfString:@"://"].location != NSNotFound) {
+        appURL = [NSURL URLWithString:self.startPage];
+    } else if ([self.wwwFolderName rangeOfString:@"://"].location != NSNotFound) {
+        appURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.wwwFolderName, self.startPage]];
+    } else if([self.wwwFolderName rangeOfString:@".bundle"].location != NSNotFound){
+        // www folder is actually a bundle
+        NSBundle* bundle = [NSBundle bundleWithPath:self.wwwFolderName];
+        appURL = [bundle URLForResource:self.startPage withExtension:nil];
+    } else if([self.wwwFolderName rangeOfString:@".framework"].location != NSNotFound){
+        // www folder is actually a framework
+        NSBundle* bundle = [NSBundle bundleWithPath:self.wwwFolderName];
+        appURL = [bundle URLForResource:self.startPage withExtension:nil];
+    } else {
+        // CB-3005 strip parameters from start page to check if page exists in resources
+        NSURL* startURL = [NSURL URLWithString:self.startPage];
+        NSString* startFilePath = [self.commandDelegate pathForResource:[startURL path]];
+
+        if (startFilePath == nil) {
+            appURL = nil;
+        } else {
+            appURL = [NSURL fileURLWithPath:startFilePath];
+            // CB-3005 Add on the query params or fragment.
+            NSString* startPageNoParentDirs = self.startPage;
+            NSRange r = [startPageNoParentDirs rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"?#"] options:0];
+            if (r.location != NSNotFound) {
+                NSString* queryAndOrFragment = [self.startPage substringFromIndex:r.location];
+                appURL = [NSURL URLWithString:queryAndOrFragment relativeToURL:appURL];
+            }
+        }
+    }
+
+    return appURL;
+}
+
+- (NSURL*)errorURL
+{
+    NSURL* errorUrl = nil;
+
+    id setting = [self.settings cordovaSettingForKey:@"ErrorUrl"];
+
+    if (setting) {
+        NSString* errorUrlString = (NSString*)setting;
+        if ([errorUrlString rangeOfString:@"://"].location != NSNotFound) {
+            errorUrl = [NSURL URLWithString:errorUrlString];
+        } else {
+            NSURL* url = [NSURL URLWithString:(NSString*)setting];
+            NSString* errorFilePath = [self.commandDelegate pathForResource:[url path]];
+            if (errorFilePath) {
+                errorUrl = [NSURL fileURLWithPath:errorFilePath];
+            }
+        }
+    }
+
+    return errorUrl;
+}
+
+- (UIView*)webView
+{
+    if (self.webViewEngine != nil) {
+        return self.webViewEngine.engineWebView;
+    }
+
+    return nil;
+}
+
+// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+
+    // Load settings
+    [self loadSettings];
+
+    NSString* backupWebStorageType = @"cloud"; // default value
+
+    id backupWebStorage = [self.settings cordovaSettingForKey:@"BackupWebStorage"];
+    if ([backupWebStorage isKindOfClass:[NSString class]]) {
+        backupWebStorageType = backupWebStorage;
+    }
+    [self.settings setCordovaSetting:backupWebStorageType forKey:@"BackupWebStorage"];
+
+    // // Instantiate the Launch screen /////////
+
+    if (!self.launchView) {
+        [self createLaunchView];
+    }
+
+    // // Instantiate the WebView ///////////////
+
+    if (!self.webView) {
+        [self createGapView];
+    }
+
+    // /////////////////
+
+    if ([self.startupPluginNames count] > 0) {
+        [CDVTimer start:@"TotalPluginStartup"];
+
+        for (NSString* pluginName in self.startupPluginNames) {
+            [CDVTimer start:pluginName];
+            [self getCommandInstance:pluginName];
+            [CDVTimer stop:pluginName];
+        }
+
+        [CDVTimer stop:@"TotalPluginStartup"];
+    }
+
+    // /////////////////
+    NSURL* appURL = [self appUrl];
+
+    if (appURL) {
+        NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
+        [self.webViewEngine loadRequest:appReq];
+    } else {
+        NSString* loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage];
+        NSLog(@"%@", loadErr);
+
+        NSURL* errorUrl = [self errorURL];
+        if (errorUrl) {
+            errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [loadErr stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet]] relativeToURL:errorUrl];
+            NSLog(@"%@", [errorUrl absoluteString]);
+            [self.webViewEngine loadRequest:[NSURLRequest requestWithURL:errorUrl]];
+        } else {
+            NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
+            [self.webViewEngine loadHTMLString:html baseURL:nil];
+        }
+    }
+    // /////////////////
+
+    UIColor* bgColor = [UIColor colorNamed:@"BackgroundColor"] ?: UIColor.whiteColor;
+    [self.launchView setBackgroundColor:bgColor];
+    [self.webView setBackgroundColor:bgColor];
+}
+
+-(void)viewWillAppear:(BOOL)animated
+{
+    [super viewWillAppear:animated];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillAppearNotification object:nil]];
+}
+
+-(void)viewDidAppear:(BOOL)animated
+{
+    [super viewDidAppear:animated];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewDidAppearNotification object:nil]];
+}
+
+-(void)viewWillDisappear:(BOOL)animated
+{
+    [super viewWillDisappear:animated];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillDisappearNotification object:nil]];
+}
+
+-(void)viewDidDisappear:(BOOL)animated
+{
+    [super viewDidDisappear:animated];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewDidDisappearNotification object:nil]];
+}
+
+-(void)viewWillLayoutSubviews
+{
+    [super viewWillLayoutSubviews];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillLayoutSubviewsNotification object:nil]];
+}
+
+-(void)viewDidLayoutSubviews
+{
+    [super viewDidLayoutSubviews];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewDidLayoutSubviewsNotification object:nil]];
+}
+
+-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
+{
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillTransitionToSizeNotification object:[NSValue valueWithCGSize:size]]];
+}
+
+- (UIColor*)colorFromColorString:(NSString*)colorString
+{
+    // No value, nothing to do
+    if (!colorString) {
+        return nil;
+    }
+
+    // Validate format
+    NSError* error = NULL;
+    NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"^(#[0-9A-F]{3}|(0x|#)([0-9A-F]{2})?[0-9A-F]{6})$" options:NSRegularExpressionCaseInsensitive error:&error];
+    NSUInteger countMatches = [regex numberOfMatchesInString:colorString options:0 range:NSMakeRange(0, [colorString length])];
+
+    if (!countMatches) {
+        return nil;
+    }
+
+    // #FAB to #FFAABB
+    if ([colorString hasPrefix:@"#"] && [colorString length] == 4) {
+        NSString* r = [colorString substringWithRange:NSMakeRange(1, 1)];
+        NSString* g = [colorString substringWithRange:NSMakeRange(2, 1)];
+        NSString* b = [colorString substringWithRange:NSMakeRange(3, 1)];
+        colorString = [NSString stringWithFormat:@"#%@%@%@%@%@%@", r, r, g, g, b, b];
+    }
+
+    // #RRGGBB to 0xRRGGBB
+    colorString = [colorString stringByReplacingOccurrencesOfString:@"#" withString:@"0x"];
+
+    // 0xRRGGBB to 0xAARRGGBB
+    if ([colorString hasPrefix:@"0x"] && [colorString length] == 8) {
+        colorString = [@"0xFF" stringByAppendingString:[colorString substringFromIndex:2]];
+    }
+
+    // 0xAARRGGBB to int
+    unsigned colorValue = 0;
+    NSScanner *scanner = [NSScanner scannerWithString:colorString];
+    if (![scanner scanHexInt:&colorValue]) {
+        return nil;
+    }
+
+    // int to UIColor
+    return [UIColor colorWithRed:((float)((colorValue & 0x00FF0000) >> 16))/255.0
+                           green:((float)((colorValue & 0x0000FF00) >>  8))/255.0
+                            blue:((float)((colorValue & 0x000000FF) >>  0))/255.0
+                           alpha:((float)((colorValue & 0xFF000000) >> 24))/255.0];
+}
+
+- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
+{
+    NSMutableArray* result = [[NSMutableArray alloc] init];
+
+    if (orientations != nil) {
+        NSEnumerator* enumerator = [orientations objectEnumerator];
+        NSString* orientationString;
+
+        while (orientationString = [enumerator nextObject]) {
+            if ([orientationString isEqualToString:@"UIInterfaceOrientationPortrait"]) {
+                [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]];
+            } else if ([orientationString isEqualToString:@"UIInterfaceOrientationPortraitUpsideDown"]) {
+                [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown]];
+            } else if ([orientationString isEqualToString:@"UIInterfaceOrientationLandscapeLeft"]) {
+                [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]];
+            } else if ([orientationString isEqualToString:@"UIInterfaceOrientationLandscapeRight"]) {
+                [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight]];
+            }
+        }
+    }
+
+    // default
+    if ([result count] == 0) {
+        [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]];
+    }
+
+    return result;
+}
+
+- (BOOL)shouldAutorotate
+{
+    return YES;
+}
+
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations
+{
+    NSUInteger ret = 0;
+
+    if ([self supportsOrientation:UIInterfaceOrientationPortrait]) {
+        ret = ret | (1 << UIInterfaceOrientationPortrait);
+    }
+    if ([self supportsOrientation:UIInterfaceOrientationPortraitUpsideDown]) {
+        ret = ret | (1 << UIInterfaceOrientationPortraitUpsideDown);
+    }
+    if ([self supportsOrientation:UIInterfaceOrientationLandscapeRight]) {
+        ret = ret | (1 << UIInterfaceOrientationLandscapeRight);
+    }
+    if ([self supportsOrientation:UIInterfaceOrientationLandscapeLeft]) {
+        ret = ret | (1 << UIInterfaceOrientationLandscapeLeft);
+    }
+
+    return ret;
+}
+
+- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation
+{
+    return [self.supportedOrientations containsObject:@(orientation)];
+}
+
+- (UIView*)newCordovaViewWithFrame:(CGRect)bounds
+{
+    NSString* defaultWebViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaDefaultWebViewEngine"];
+    NSString* webViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaWebViewEngine"];
+
+    if (!defaultWebViewEngineClass) {
+        defaultWebViewEngineClass = @"CDVWebViewEngine";
+    }
+    if (!webViewEngineClass) {
+        webViewEngineClass = defaultWebViewEngineClass;
+    }
+
+    // Find webViewEngine
+    if (NSClassFromString(webViewEngineClass)) {
+        self.webViewEngine = [[NSClassFromString(webViewEngineClass) alloc] initWithFrame:bounds];
+        // if a webView engine returns nil (not supported by the current iOS version) or doesn't conform to the protocol, or can't load the request, we use WKWebView
+        if (!self.webViewEngine || ![self.webViewEngine conformsToProtocol:@protocol(CDVWebViewEngineProtocol)] || ![self.webViewEngine canLoadRequest:[NSURLRequest requestWithURL:self.appUrl]]) {
+            self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds];
+        }
+    } else {
+        self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds];
+    }
+
+    if ([self.webViewEngine isKindOfClass:[CDVPlugin class]]) {
+        [self registerPlugin:(CDVPlugin*)self.webViewEngine withClassName:webViewEngineClass];
+    }
+
+    return self.webViewEngine.engineWebView;
+}
+
+- (void)createLaunchView
+{
+    CGRect webViewBounds = self.view.bounds;
+    webViewBounds.origin = self.view.bounds.origin;
+
+    UIView* view = [[UIView alloc] initWithFrame:webViewBounds];
+
+    NSString* launchStoryboardName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
+    if (launchStoryboardName != nil) {
+        UIStoryboard* storyboard = [UIStoryboard storyboardWithName:launchStoryboardName bundle:[NSBundle mainBundle]];
+        UIViewController* vc = [storyboard instantiateInitialViewController];
+
+        [view addSubview:vc.view];
+    }
+
+    self.launchView = view;
+    [self.view addSubview:view];
+}
+
+- (void)createGapView
+{
+    CGRect webViewBounds = self.view.bounds;
+    webViewBounds.origin = self.view.bounds.origin;
+
+    UIView* view = [self newCordovaViewWithFrame:webViewBounds];
+    view.hidden = YES;
+    view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
+
+    [self.view addSubview:view];
+    [self.view sendSubviewToBack:view];
+}
+
+- (void)didReceiveMemoryWarning
+{
+    // iterate through all the plugin objects, and call hasPendingOperation
+    // if at least one has a pending operation, we don't call [super didReceiveMemoryWarning]
+
+    NSEnumerator* enumerator = [self.pluginObjects objectEnumerator];
+    CDVPlugin* plugin;
+
+    BOOL doPurge = YES;
+
+    while ((plugin = [enumerator nextObject])) {
+        if (plugin.hasPendingOperation) {
+            NSLog(@"Plugin '%@' has a pending operation, memory purge is delayed for didReceiveMemoryWarning.", NSStringFromClass([plugin class]));
+            doPurge = NO;
+        }
+    }
+
+    if (doPurge) {
+        // Releases the view if it doesn't have a superview.
+        [super didReceiveMemoryWarning];
+    }
+
+    // Release any cached data, images, etc. that aren't in use.
+}
+
+#pragma mark CordovaCommands
+
+- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className
+{
+    if ([plugin respondsToSelector:@selector(setViewController:)]) {
+        [plugin setViewController:self];
+    }
+
+    if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) {
+        [plugin setCommandDelegate:_commandDelegate];
+    }
+
+    [self.pluginObjects setObject:plugin forKey:className];
+    [plugin pluginInitialize];
+}
+
+- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName
+{
+    if ([plugin respondsToSelector:@selector(setViewController:)]) {
+        [plugin setViewController:self];
+    }
+
+    if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) {
+        [plugin setCommandDelegate:_commandDelegate];
+    }
+
+    NSString* className = NSStringFromClass([plugin class]);
+    [self.pluginObjects setObject:plugin forKey:className];
+    [self.pluginsMap setValue:className forKey:[pluginName lowercaseString]];
+    [plugin pluginInitialize];
+}
+
+/**
+ Returns an instance of a CordovaCommand object, based on its name.  If one exists already, it is returned.
+ */
+- (id)getCommandInstance:(NSString*)pluginName
+{
+    // first, we try to find the pluginName in the pluginsMap
+    // (acts as a whitelist as well) if it does not exist, we return nil
+    // NOTE: plugin names are matched as lowercase to avoid problems - however, a
+    // possible issue is there can be duplicates possible if you had:
+    // "org.apache.cordova.Foo" and "org.apache.cordova.foo" - only the lower-cased entry will match
+    NSString* className = [self.pluginsMap objectForKey:[pluginName lowercaseString]];
+
+    if (className == nil) {
+        return nil;
+    }
+
+    id obj = [self.pluginObjects objectForKey:className];
+    if (!obj) {
+        obj = [[NSClassFromString(className)alloc] initWithWebViewEngine:_webViewEngine];
+        if (!obj) {
+            NSString* fullClassName = [NSString stringWithFormat:@"%@.%@",
+                                       NSBundle.mainBundle.infoDictionary[@"CFBundleExecutable"],
+                                       className];
+            obj = [[NSClassFromString(fullClassName)alloc] initWithWebViewEngine:_webViewEngine];
+        }
+
+        if (obj != nil) {
+            [self registerPlugin:obj withClassName:className];
+        } else {
+            NSLog(@"CDVPlugin class %@ (pluginName: %@) does not exist.", className, pluginName);
+        }
+    }
+    return obj;
+}
+
+#pragma mark -
+
+- (NSString*)appURLScheme
+{
+    NSString* URLScheme = nil;
+
+    NSArray* URLTypes = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleURLTypes"];
+
+    if (URLTypes != nil) {
+        NSDictionary* dict = [URLTypes objectAtIndex:0];
+        if (dict != nil) {
+            NSArray* URLSchemes = [dict objectForKey:@"CFBundleURLSchemes"];
+            if (URLSchemes != nil) {
+                URLScheme = [URLSchemes objectAtIndex:0];
+            }
+        }
+    }
+
+    return URLScheme;
+}
+
+#pragma mark -
+#pragma mark UIApplicationDelegate impl
+
+/*
+ This method lets your application know that it is about to be terminated and purged from memory entirely
+ */
+- (void)onAppWillTerminate:(NSNotification*)notification
+{
+    // empty the tmp directory
+    NSFileManager* fileMgr = [[NSFileManager alloc] init];
+    NSError* __autoreleasing err = nil;
+
+    // clear contents of NSTemporaryDirectory
+    NSString* tempDirectoryPath = NSTemporaryDirectory();
+    NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath];
+    NSString* fileName = nil;
+    BOOL result;
+
+    while ((fileName = [directoryEnumerator nextObject])) {
+        NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName];
+        result = [fileMgr removeItemAtPath:filePath error:&err];
+        if (!result && err) {
+            NSLog(@"Failed to delete: %@ (error: %@)", filePath, err);
+        }
+    }
+}
+
+- (bool)isUrlEmpty:(NSURL *)url
+{
+    if (!url || (url == (id) [NSNull null])) {
+        return true;
+    }
+    NSString *urlAsString = [url absoluteString];
+    return (urlAsString == (id) [NSNull null] || [urlAsString length]==0 || [urlAsString isEqualToString:@"about:blank"]);
+}
+
+- (bool)checkAndReinitViewUrl
+{
+    NSURL* appURL = [self appUrl];
+    if ([self isUrlEmpty: [self.webViewEngine URL]] && ![self isUrlEmpty: appURL]) {
+        NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
+        [self.webViewEngine loadRequest:appReq];
+        return true;
+    }
+    return false;
+}
+
+/*
+ This method is called to let your application know that it is about to move from the active to inactive state.
+ You should use this method to pause ongoing tasks, disable timer, ...
+ */
+- (void)onAppWillResignActive:(NSNotification*)notification
+{
+    [self checkAndReinitViewUrl];
+    // NSLog(@"%@",@"applicationWillResignActive");
+    [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('resign');" scheduledOnRunLoop:NO];
+}
+
+/*
+ In iOS 4.0 and later, this method is called as part of the transition from the background to the inactive state.
+ You can use this method to undo many of the changes you made to your application upon entering the background.
+ invariably followed by applicationDidBecomeActive
+ */
+- (void)onAppWillEnterForeground:(NSNotification*)notification
+{
+    [self checkAndReinitViewUrl];
+    // NSLog(@"%@",@"applicationWillEnterForeground");
+    [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('resume');"];
+
+    if (!IsAtLeastiOSVersion(@"11.0")) {
+        /** Clipboard fix **/
+        UIPasteboard* pasteboard = [UIPasteboard generalPasteboard];
+        NSString* string = pasteboard.string;
+        if (string) {
+            [pasteboard setValue:string forPasteboardType:@"public.text"];
+        }
+    }
+}
+
+// This method is called to let your application know that it moved from the inactive to active state.
+- (void)onAppDidBecomeActive:(NSNotification*)notification
+{
+    [self checkAndReinitViewUrl];
+    // NSLog(@"%@",@"applicationDidBecomeActive");
+    [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('active');"];
+}
+
+/*
+ In iOS 4.0 and later, this method is called instead of the applicationWillTerminate: method
+ when the user quits an application that supports background execution.
+ */
+- (void)onAppDidEnterBackground:(NSNotification*)notification
+{
+    [self checkAndReinitViewUrl];
+    // NSLog(@"%@",@"applicationDidEnterBackground");
+    [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('pause', null, true);" scheduledOnRunLoop:NO];
+}
+
+/**
+ Show the webview and fade out the intermediary view
+ This is to prevent the flashing of the mainViewController
+ */
+- (void)onWebViewPageDidLoad:(NSNotification*)notification
+{
+    self.webView.hidden = NO;
+
+    if ([self.settings cordovaBoolSettingForKey:@"AutoHideSplashScreen" defaultValue:YES]) {
+       [self showLaunchScreen:NO];
+    }
+}
+
+/**
+ Method to be called from the plugin JavaScript to show or hide the launch screen.
+ */
+- (void)showLaunchScreen:(BOOL)visible
+{
+    CGFloat splashScreenDelay = [self.settings cordovaFloatSettingForKey:@"SplashScreenDelay" defaultValue:0];
+
+    // AnimateWithDuration takes seconds but cordova documentation specifies milliseconds
+    CGFloat fadeSplashScreenDuration = [self.settings cordovaFloatSettingForKey:@"FadeSplashScreenDuration" defaultValue:250];
+
+    // Setting minimum value for fade to 0.25 seconds
+    fadeSplashScreenDuration = fadeSplashScreenDuration < 250 ? 250 : fadeSplashScreenDuration;
+
+    // Divide by 1000 because config returns milliseconds and NSTimer takes seconds
+    CGFloat delayToFade = (MAX(splashScreenDelay, fadeSplashScreenDuration) - fadeSplashScreenDuration)/1000;
+    CGFloat fadeDuration = fadeSplashScreenDuration/1000;
+
+    [NSTimer scheduledTimerWithTimeInterval:delayToFade repeats:NO block:^(NSTimer * _Nonnull timer) {
+        [UIView animateWithDuration:fadeDuration animations:^{
+            [self.launchView setAlpha:(visible ? 1 : 0)];
+        }];
+    }];
+}
+
+// ///////////////////////
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+    [_commandQueue dispose];
+    [[self.pluginObjects allValues] makeObjectsPerformSelector:@selector(dispose)];
+
+    [self.webViewEngine loadHTMLString:@"about:blank" baseURL:nil];
+    [self.pluginObjects removeAllObjects];
+    [self.webView removeFromSuperview];
+    self.webViewEngine = nil;
+}
+
+@end

+ 41 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVWebViewEngineProtocol.h

@@ -0,0 +1,41 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+#define kCDVWebViewEngineScriptMessageHandlers @"kCDVWebViewEngineScriptMessageHandlers"
+#define kCDVWebViewEngineWKNavigationDelegate @"kCDVWebViewEngineWKNavigationDelegate"
+#define kCDVWebViewEngineWKUIDelegate @"kCDVWebViewEngineWKUIDelegate"
+#define kCDVWebViewEngineWebViewPreferences @"kCDVWebViewEngineWebViewPreferences"
+
+@protocol CDVWebViewEngineProtocol <NSObject>
+
+@property (nonatomic, strong, readonly) UIView* engineWebView;
+
+- (id)loadRequest:(NSURLRequest*)request;
+- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL;
+- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^)(id, NSError*))completionHandler;
+
+- (NSURL*)URL;
+- (BOOL)canLoadRequest:(NSURLRequest*)request;
+
+- (instancetype)initWithFrame:(CGRect)frame;
+- (void)updateWithInfo:(NSDictionary*)info;
+
+@end

+ 34 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVWhitelist.h

@@ -0,0 +1,34 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+extern NSString* const kCDVDefaultWhitelistRejectionString;
+
+@interface CDVWhitelist : NSObject
+
+@property (nonatomic, copy) NSString* whitelistRejectionFormatString;
+
+- (id)initWithArray:(NSArray*)array;
+- (BOOL)schemeIsAllowed:(NSString*)scheme;
+- (BOOL)URLIsAllowed:(NSURL*)url;
+- (BOOL)URLIsAllowed:(NSURL*)url logFailure:(BOOL)logFailure;
+- (NSString*)errorStringForURL:(NSURL*)url;
+
+@end

+ 285 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/CDVWhitelist.m

@@ -0,0 +1,285 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVWhitelist.h"
+
+NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejection: url='%@'";
+NSString* const kCDVDefaultSchemeName = @"cdv-default-scheme";
+
+@interface CDVWhitelistPattern : NSObject {
+    @private
+    NSRegularExpression* _scheme;
+    NSRegularExpression* _host;
+    NSNumber* _port;
+    NSRegularExpression* _path;
+}
+
++ (NSString*)regexFromPattern:(NSString*)pattern allowWildcards:(bool)allowWildcards;
+- (id)initWithScheme:(NSString*)scheme host:(NSString*)host port:(NSString*)port path:(NSString*)path;
+- (bool)matches:(NSURL*)url;
+
+@end
+
+@implementation CDVWhitelistPattern
+
++ (NSString*)regexFromPattern:(NSString*)pattern allowWildcards:(bool)allowWildcards
+{
+    NSString* regex = [NSRegularExpression escapedPatternForString:pattern];
+
+    if (allowWildcards) {
+        regex = [regex stringByReplacingOccurrencesOfString:@"\\*" withString:@".*"];
+
+        /* [NSURL path] has the peculiarity that a trailing slash at the end of a path
+         * will be omitted. This regex tweak compensates for that.
+         */
+        if ([regex hasSuffix:@"\\/.*"]) {
+            regex = [NSString stringWithFormat:@"%@(\\/.*)?", [regex substringToIndex:([regex length] - 4)]];
+        }
+    }
+    return [NSString stringWithFormat:@"%@$", regex];
+}
+
+- (id)initWithScheme:(NSString*)scheme host:(NSString*)host port:(NSString*)port path:(NSString*)path
+{
+    self = [super init];  // Potentially change "self"
+    if (self) {
+        if ((scheme == nil) || [scheme isEqualToString:@"*"]) {
+            _scheme = nil;
+        } else {
+            _scheme = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:scheme allowWildcards:NO] options:NSRegularExpressionCaseInsensitive error:nil];
+        }
+        if ([host isEqualToString:@"*"] || host == nil) {
+            _host = nil;
+        } else if ([host hasPrefix:@"*."]) {
+            _host = [NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"([a-z0-9.-]*\\.)?%@", [CDVWhitelistPattern regexFromPattern:[host substringFromIndex:2] allowWildcards:false]] options:NSRegularExpressionCaseInsensitive error:nil];
+        } else {
+            _host = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:host allowWildcards:NO] options:NSRegularExpressionCaseInsensitive error:nil];
+        }
+        if ((port == nil) || [port isEqualToString:@"*"]) {
+            _port = nil;
+        } else {
+            _port = [[NSNumber alloc] initWithInteger:[port integerValue]];
+        }
+        if ((path == nil) || [path isEqualToString:@"/*"]) {
+            _path = nil;
+        } else {
+            _path = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:path allowWildcards:YES] options:0 error:nil];
+        }
+    }
+    return self;
+}
+
+- (bool)matches:(NSURL*)url
+{
+    return (_scheme == nil || [_scheme numberOfMatchesInString:[url scheme] options:NSMatchingAnchored range:NSMakeRange(0, [[url scheme] length])]) &&
+           (_host == nil || ([url host] != nil && [_host numberOfMatchesInString:[url host] options:NSMatchingAnchored range:NSMakeRange(0, [[url host] length])])) &&
+           (_port == nil || [[url port] isEqualToNumber:_port]) &&
+           (_path == nil || [_path numberOfMatchesInString:[url path] options:NSMatchingAnchored range:NSMakeRange(0, [[url path] length])])
+    ;
+}
+
+@end
+
+@interface CDVWhitelist ()
+
+@property (nonatomic, readwrite, strong) NSMutableArray* whitelist;
+@property (nonatomic, readwrite, strong) NSMutableSet* permittedSchemes;
+
+- (void)addWhiteListEntry:(NSString*)pattern;
+
+@end
+
+@implementation CDVWhitelist
+
+@synthesize whitelist, permittedSchemes, whitelistRejectionFormatString;
+
+- (id)initWithArray:(NSArray*)array
+{
+    self = [super init];
+    if (self) {
+        self.whitelist = [[NSMutableArray alloc] init];
+        self.permittedSchemes = [[NSMutableSet alloc] init];
+        self.whitelistRejectionFormatString = kCDVDefaultWhitelistRejectionString;
+
+        for (NSString* pattern in array) {
+            [self addWhiteListEntry:pattern];
+        }
+    }
+    return self;
+}
+
+- (BOOL)isIPv4Address:(NSString*)externalHost
+{
+    // an IPv4 address has 4 octets b.b.b.b where b is a number between 0 and 255.
+    // for our purposes, b can also be the wildcard character '*'
+
+    // we could use a regex to solve this problem but then I would have two problems
+    // anyways, this is much clearer and maintainable
+    NSArray* octets = [externalHost componentsSeparatedByString:@"."];
+    NSUInteger num_octets = [octets count];
+
+    // quick check
+    if (num_octets != 4) {
+        return NO;
+    }
+
+    // restrict number parsing to 0-255
+    NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
+    [numberFormatter setMinimum:[NSNumber numberWithUnsignedInteger:0]];
+    [numberFormatter setMaximum:[NSNumber numberWithUnsignedInteger:255]];
+
+    // iterate through each octet, and test for a number between 0-255 or if it equals '*'
+    for (NSUInteger i = 0; i < num_octets; ++i) {
+        NSString* octet = [octets objectAtIndex:i];
+
+        if ([octet isEqualToString:@"*"]) { // passes - check next octet
+            continue;
+        } else if ([numberFormatter numberFromString:octet] == nil) { // fails - not a number and not within our range, return
+            return NO;
+        }
+    }
+
+    return YES;
+}
+
+- (void)addWhiteListEntry:(NSString*)origin
+{
+    if (self.whitelist == nil) {
+        return;
+    }
+
+    if ([origin isEqualToString:@"*"]) {
+        NSLog(@"Unlimited access to network resources");
+        self.whitelist = nil;
+        self.permittedSchemes = nil;
+    } else { // specific access
+        NSRegularExpression* parts = [NSRegularExpression regularExpressionWithPattern:@"^((\\*|[A-Za-z-]+):/?/?)?(((\\*\\.)?[^*/:]+)|\\*)?(:(\\d+))?(/.*)?" options:0 error:nil];
+        NSTextCheckingResult* m = [parts firstMatchInString:origin options:NSMatchingAnchored range:NSMakeRange(0, [origin length])];
+        if (m != nil) {
+            NSRange r;
+            NSString* scheme = nil;
+            r = [m rangeAtIndex:2];
+            if (r.location != NSNotFound) {
+                scheme = [origin substringWithRange:r];
+            }
+
+            NSString* host = nil;
+            r = [m rangeAtIndex:3];
+            if (r.location != NSNotFound) {
+                host = [origin substringWithRange:r];
+            }
+
+            // Special case for two urls which are allowed to have empty hosts
+            if (([scheme isEqualToString:@"file"] || [scheme isEqualToString:@"content"]) && (host == nil)) {
+                host = @"*";
+            }
+
+            NSString* port = nil;
+            r = [m rangeAtIndex:7];
+            if (r.location != NSNotFound) {
+                port = [origin substringWithRange:r];
+            }
+
+            NSString* path = nil;
+            r = [m rangeAtIndex:8];
+            if (r.location != NSNotFound) {
+                path = [origin substringWithRange:r];
+            }
+
+            if (scheme == nil) {
+                // XXX making it stupid friendly for people who forget to include protocol/SSL
+                [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:@"http" host:host port:port path:path]];
+                [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:@"https" host:host port:port path:path]];
+            } else {
+                [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:scheme host:host port:port path:path]];
+            }
+
+            if (self.permittedSchemes != nil) {
+                if ([scheme isEqualToString:@"*"]) {
+                    self.permittedSchemes = nil;
+                } else if (scheme != nil) {
+                    [self.permittedSchemes addObject:scheme];
+                }
+            }
+        }
+    }
+}
+
+- (BOOL)schemeIsAllowed:(NSString*)scheme
+{
+    if ([scheme isEqualToString:@"http"] ||
+        [scheme isEqualToString:@"https"] ||
+        [scheme isEqualToString:@"ftp"] ||
+        [scheme isEqualToString:@"ftps"]) {
+        return YES;
+    }
+
+    return (self.permittedSchemes == nil) || [self.permittedSchemes containsObject:scheme];
+}
+
+- (BOOL)URLIsAllowed:(NSURL*)url
+{
+    return [self URLIsAllowed:url logFailure:YES];
+}
+
+- (BOOL)URLIsAllowed:(NSURL*)url logFailure:(BOOL)logFailure
+{
+    // Shortcut acceptance: Are all urls whitelisted ("*" in whitelist)?
+    if (whitelist == nil) {
+        return YES;
+    }
+
+    // Shortcut rejection: Check that the scheme is supported
+    NSString* scheme = [[url scheme] lowercaseString];
+    if (![self schemeIsAllowed:scheme]) {
+        if (logFailure) {
+            NSLog(@"%@", [self errorStringForURL:url]);
+        }
+        return NO;
+    }
+
+    // http[s] and ftp[s] should also validate against the common set in the kCDVDefaultSchemeName list
+    if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"ftp"] || [scheme isEqualToString:@"ftps"]) {
+        NSURL* newUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@%@", kCDVDefaultSchemeName, [url host], [[url path] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet]]];
+        // If it is allowed, we are done.  If not, continue to check for the actual scheme-specific list
+        if ([self URLIsAllowed:newUrl logFailure:NO]) {
+            return YES;
+        }
+    }
+
+    // Check the url against patterns in the whitelist
+    for (CDVWhitelistPattern* p in self.whitelist) {
+        if ([p matches:url]) {
+            return YES;
+        }
+    }
+
+    if (logFailure) {
+        NSLog(@"%@", [self errorStringForURL:url]);
+    }
+    // if we got here, the url host is not in the white-list, do nothing
+    return NO;
+}
+
+- (NSString*)errorStringForURL:(NSURL*)url
+{
+    return [NSString stringWithFormat:self.whitelistRejectionFormatString, [url absoluteString]];
+}
+
+@end

+ 35 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/NSDictionary+CordovaPreferences.h

@@ -0,0 +1,35 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface NSDictionary (CordovaPreferences)
+
+- (id)cordovaSettingForKey:(NSString*)key;
+- (BOOL)cordovaBoolSettingForKey:(NSString*)key defaultValue:(BOOL)defaultValue;
+- (CGFloat)cordovaFloatSettingForKey:(NSString*)key defaultValue:(CGFloat)defaultValue;
+
+@end
+
+@interface NSMutableDictionary (CordovaPreferences)
+
+- (void)setCordovaSetting:(id)value forKey:(NSString*)key;
+
+@end

+ 92 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/NSDictionary+CordovaPreferences.m

@@ -0,0 +1,92 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "NSDictionary+CordovaPreferences.h"
+#import <Foundation/Foundation.h>
+
+@implementation NSDictionary (CordovaPreferences)
+
+- (id)cordovaSettingForKey:(NSString*)key
+{
+    return [self objectForKey:[key lowercaseString]];
+}
+
+- (BOOL)cordovaBoolSettingForKey:(NSString*)key defaultValue:(BOOL)defaultValue
+{
+    BOOL value = defaultValue;
+    id prefObj = [self cordovaSettingForKey:key];
+
+    if (prefObj == nil) {
+        NSLog(@"The preference key \"%@\" is not defined and will default to \"%@\"",
+              key,
+              (defaultValue ? @"TRUE" : @"FALSE"));
+
+        return value;
+    }
+
+    if ([prefObj isKindOfClass:NSString.class]) {
+        prefObj = [prefObj lowercaseString];
+
+        if (
+            // True Case
+            [prefObj isEqualToString:@"true"] ||
+            [prefObj isEqualToString:@"1"] ||
+            // False Case
+            [prefObj isEqualToString:@"false"] ||
+            [prefObj isEqualToString:@"0"]
+            )
+        {
+            value = [prefObj isEqualToString:@"true"] || [prefObj isEqualToString:@"1"];
+        }
+    } else if (
+               [prefObj isKindOfClass:NSNumber.class] &&
+               (
+                [prefObj isEqual: @YES] ||
+                [prefObj isEqual: @NO]
+                )
+               )
+    {
+        value = [prefObj isEqual: @YES];
+    }
+
+    return value;
+}
+
+- (CGFloat)cordovaFloatSettingForKey:(NSString*)key defaultValue:(CGFloat)defaultValue
+{
+    CGFloat value = defaultValue;
+    id prefObj = [self cordovaSettingForKey:key];
+
+    if (prefObj != nil) {
+        value = [prefObj floatValue];
+    }
+
+    return value;
+}
+
+@end
+
+@implementation NSMutableDictionary (CordovaPreferences)
+
+- (void)setCordovaSetting:(id)value forKey:(NSString*)key
+{
+    [self setObject:value forKey:[key lowercaseString]];
+}
+
+@end

+ 29 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/NSMutableArray+QueueAdditions.h

@@ -0,0 +1,29 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface NSMutableArray (QueueAdditions)
+
+- (id)cdv_pop;
+- (id)cdv_queueHead;
+- (id)cdv_dequeue;
+- (void)cdv_enqueue:(id)obj;
+
+@end

+ 58 - 0
cordova/platforms/ios/CordovaLib/Classes/Public/NSMutableArray+QueueAdditions.m

@@ -0,0 +1,58 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "NSMutableArray+QueueAdditions.h"
+
+@implementation NSMutableArray (QueueAdditions)
+
+- (id)cdv_queueHead
+{
+    if ([self count] == 0) {
+        return nil;
+    }
+
+    return [self objectAtIndex:0];
+}
+
+- (__autoreleasing id)cdv_dequeue
+{
+    if ([self count] == 0) {
+        return nil;
+    }
+
+    id head = [self objectAtIndex:0];
+    if (head != nil) {
+        // [[head retain] autorelease]; ARC - the __autoreleasing on the return value should so the same thing
+        [self removeObjectAtIndex:0];
+    }
+
+    return head;
+}
+
+- (id)cdv_pop
+{
+    return [self cdv_dequeue];
+}
+
+- (void)cdv_enqueue:(id)object
+{
+    [self addObject:object];
+}
+
+@end

+ 791 - 0
cordova/platforms/ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj

@@ -0,0 +1,791 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 52;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		28BFF9141F355A4E00DDF01A /* CDVLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BFF9121F355A4E00DDF01A /* CDVLogger.h */; };
+		28BFF9151F355A4E00DDF01A /* CDVLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 28BFF9131F355A4E00DDF01A /* CDVLogger.m */; };
+		2F4D42BC23F218BA00501999 /* CDVURLSchemeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F4D42BA23F218BA00501999 /* CDVURLSchemeHandler.h */; };
+		2F4D42BD23F218BA00501999 /* CDVURLSchemeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F4D42BB23F218BA00501999 /* CDVURLSchemeHandler.m */; };
+		2FCCEA17247E7366007276A8 /* CDVLaunchScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E714D3423F535B500A321AF /* CDVLaunchScreen.m */; };
+		2FCCEA18247E7366007276A8 /* CDVLaunchScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E714D3223F535B500A321AF /* CDVLaunchScreen.h */; };
+		3093E2231B16D6A3003F381A /* CDVIntentAndNavigationFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3093E2211B16D6A3003F381A /* CDVIntentAndNavigationFilter.h */; };
+		3093E2241B16D6A3003F381A /* CDVIntentAndNavigationFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3093E2221B16D6A3003F381A /* CDVIntentAndNavigationFilter.m */; };
+		4E23F8FB23E16E96006CD852 /* CDVWebViewProcessPoolFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E23F8F523E16E96006CD852 /* CDVWebViewProcessPoolFactory.m */; };
+		4E23F8FC23E16E96006CD852 /* CDVWebViewUIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E23F8F623E16E96006CD852 /* CDVWebViewUIDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		4E23F8FD23E16E96006CD852 /* CDVWebViewUIDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E23F8F723E16E96006CD852 /* CDVWebViewUIDelegate.m */; };
+		4E23F8FE23E16E96006CD852 /* CDVWebViewEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E23F8F823E16E96006CD852 /* CDVWebViewEngine.m */; };
+		4E23F8FF23E16E96006CD852 /* CDVWebViewProcessPoolFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E23F8F923E16E96006CD852 /* CDVWebViewProcessPoolFactory.h */; };
+		4E23F90023E16E96006CD852 /* CDVWebViewEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E23F8FA23E16E96006CD852 /* CDVWebViewEngine.h */; };
+		4E23F90323E17FFA006CD852 /* CDVWebViewUIDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E23F8F623E16E96006CD852 /* CDVWebViewUIDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		4E714D3623F535B500A321AF /* CDVLaunchScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E714D3223F535B500A321AF /* CDVLaunchScreen.h */; };
+		4E714D3823F535B500A321AF /* CDVLaunchScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E714D3423F535B500A321AF /* CDVLaunchScreen.m */; };
+		7E7F69B91ABA3692007546F4 /* CDVHandleOpenURL.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF81AB9028C008C4574 /* CDVHandleOpenURL.h */; };
+		7ED95D021AB9028C008C4574 /* CDVDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF21AB9028C008C4574 /* CDVDebug.h */; };
+		7ED95D031AB9028C008C4574 /* CDVJSON_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF31AB9028C008C4574 /* CDVJSON_private.h */; };
+		7ED95D041AB9028C008C4574 /* CDVJSON_private.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95CF41AB9028C008C4574 /* CDVJSON_private.m */; };
+		7ED95D051AB9028C008C4574 /* CDVPlugin+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF51AB9028C008C4574 /* CDVPlugin+Private.h */; };
+		7ED95D071AB9028C008C4574 /* CDVHandleOpenURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95CF91AB9028C008C4574 /* CDVHandleOpenURL.m */; };
+		7ED95D351AB9029B008C4574 /* CDV.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D0F1AB9029B008C4574 /* CDV.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D361AB9029B008C4574 /* CDVAppDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D101AB9029B008C4574 /* CDVAppDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D371AB9029B008C4574 /* CDVAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D111AB9029B008C4574 /* CDVAppDelegate.m */; };
+		7ED95D381AB9029B008C4574 /* CDVAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D121AB9029B008C4574 /* CDVAvailability.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D391AB9029B008C4574 /* CDVAvailabilityDeprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D131AB9029B008C4574 /* CDVAvailabilityDeprecated.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D3A1AB9029B008C4574 /* CDVCommandDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D141AB9029B008C4574 /* CDVCommandDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D3B1AB9029B008C4574 /* CDVCommandDelegateImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D151AB9029B008C4574 /* CDVCommandDelegateImpl.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D3C1AB9029B008C4574 /* CDVCommandDelegateImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D161AB9029B008C4574 /* CDVCommandDelegateImpl.m */; };
+		7ED95D3D1AB9029B008C4574 /* CDVCommandQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D171AB9029B008C4574 /* CDVCommandQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D3E1AB9029B008C4574 /* CDVCommandQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D181AB9029B008C4574 /* CDVCommandQueue.m */; };
+		7ED95D3F1AB9029B008C4574 /* CDVConfigParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D191AB9029B008C4574 /* CDVConfigParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D401AB9029B008C4574 /* CDVConfigParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D1A1AB9029B008C4574 /* CDVConfigParser.m */; };
+		7ED95D411AB9029B008C4574 /* CDVInvokedUrlCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D1B1AB9029B008C4574 /* CDVInvokedUrlCommand.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D421AB9029B008C4574 /* CDVInvokedUrlCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D1C1AB9029B008C4574 /* CDVInvokedUrlCommand.m */; };
+		7ED95D431AB9029B008C4574 /* CDVPlugin+Resources.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D1D1AB9029B008C4574 /* CDVPlugin+Resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D441AB9029B008C4574 /* CDVPlugin+Resources.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D1E1AB9029B008C4574 /* CDVPlugin+Resources.m */; };
+		7ED95D451AB9029B008C4574 /* CDVPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D1F1AB9029B008C4574 /* CDVPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D461AB9029B008C4574 /* CDVPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D201AB9029B008C4574 /* CDVPlugin.m */; };
+		7ED95D471AB9029B008C4574 /* CDVPluginResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D211AB9029B008C4574 /* CDVPluginResult.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D481AB9029B008C4574 /* CDVPluginResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D221AB9029B008C4574 /* CDVPluginResult.m */; };
+		7ED95D491AB9029B008C4574 /* CDVScreenOrientationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D231AB9029B008C4574 /* CDVScreenOrientationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D4A1AB9029B008C4574 /* CDVTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D241AB9029B008C4574 /* CDVTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D4B1AB9029B008C4574 /* CDVTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D251AB9029B008C4574 /* CDVTimer.m */; };
+		7ED95D501AB9029B008C4574 /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D2A1AB9029B008C4574 /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D511AB9029B008C4574 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D2B1AB9029B008C4574 /* CDVViewController.m */; };
+		7ED95D521AB9029B008C4574 /* CDVWebViewEngineProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D2C1AB9029B008C4574 /* CDVWebViewEngineProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D531AB9029B008C4574 /* CDVWhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D2D1AB9029B008C4574 /* CDVWhitelist.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D541AB9029B008C4574 /* CDVWhitelist.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D2E1AB9029B008C4574 /* CDVWhitelist.m */; };
+		7ED95D571AB9029B008C4574 /* NSDictionary+CordovaPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D311AB9029B008C4574 /* NSDictionary+CordovaPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D581AB9029B008C4574 /* NSDictionary+CordovaPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D321AB9029B008C4574 /* NSDictionary+CordovaPreferences.m */; };
+		7ED95D591AB9029B008C4574 /* NSMutableArray+QueueAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D331AB9029B008C4574 /* NSMutableArray+QueueAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7ED95D5A1AB9029B008C4574 /* NSMutableArray+QueueAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D341AB9029B008C4574 /* NSMutableArray+QueueAdditions.m */; };
+		9052DE712150D040008E83D4 /* CDVAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D111AB9029B008C4574 /* CDVAppDelegate.m */; };
+		9052DE722150D040008E83D4 /* CDVCommandDelegateImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D161AB9029B008C4574 /* CDVCommandDelegateImpl.m */; };
+		9052DE732150D040008E83D4 /* CDVCommandQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D181AB9029B008C4574 /* CDVCommandQueue.m */; };
+		9052DE742150D040008E83D4 /* CDVConfigParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D1A1AB9029B008C4574 /* CDVConfigParser.m */; };
+		9052DE752150D040008E83D4 /* CDVInvokedUrlCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D1C1AB9029B008C4574 /* CDVInvokedUrlCommand.m */; };
+		9052DE762150D040008E83D4 /* CDVPlugin+Resources.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D1E1AB9029B008C4574 /* CDVPlugin+Resources.m */; };
+		9052DE772150D040008E83D4 /* CDVPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D201AB9029B008C4574 /* CDVPlugin.m */; };
+		9052DE782150D040008E83D4 /* CDVPluginResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D221AB9029B008C4574 /* CDVPluginResult.m */; };
+		9052DE792150D040008E83D4 /* CDVTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D251AB9029B008C4574 /* CDVTimer.m */; };
+		9052DE7C2150D040008E83D4 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D2B1AB9029B008C4574 /* CDVViewController.m */; };
+		9052DE7D2150D040008E83D4 /* CDVWhitelist.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D2E1AB9029B008C4574 /* CDVWhitelist.m */; };
+		9052DE7E2150D040008E83D4 /* NSDictionary+CordovaPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D321AB9029B008C4574 /* NSDictionary+CordovaPreferences.m */; };
+		9052DE7F2150D040008E83D4 /* NSMutableArray+QueueAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95D341AB9029B008C4574 /* NSMutableArray+QueueAdditions.m */; };
+		9052DE802150D040008E83D4 /* CDVJSON_private.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95CF41AB9028C008C4574 /* CDVJSON_private.m */; };
+		9052DE812150D040008E83D4 /* CDVLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 28BFF9131F355A4E00DDF01A /* CDVLogger.m */; };
+		9052DE822150D040008E83D4 /* CDVGestureHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = A3B082D31BB15CEA00D8DC35 /* CDVGestureHandler.m */; };
+		9052DE832150D040008E83D4 /* CDVIntentAndNavigationFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3093E2221B16D6A3003F381A /* CDVIntentAndNavigationFilter.m */; };
+		9052DE842150D040008E83D4 /* CDVHandleOpenURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ED95CF91AB9028C008C4574 /* CDVHandleOpenURL.m */; };
+		9052DE892150D06B008E83D4 /* CDVDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF21AB9028C008C4574 /* CDVDebug.h */; };
+		9052DE8A2150D06B008E83D4 /* CDVJSON_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF31AB9028C008C4574 /* CDVJSON_private.h */; };
+		9052DE8B2150D06B008E83D4 /* CDVPlugin+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF51AB9028C008C4574 /* CDVPlugin+Private.h */; };
+		9052DE8C2150D06B008E83D4 /* CDVLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BFF9121F355A4E00DDF01A /* CDVLogger.h */; };
+		9052DE8D2150D06B008E83D4 /* CDVGestureHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = A3B082D21BB15CEA00D8DC35 /* CDVGestureHandler.h */; };
+		9052DE8E2150D06B008E83D4 /* CDVIntentAndNavigationFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3093E2211B16D6A3003F381A /* CDVIntentAndNavigationFilter.h */; };
+		9052DE8F2150D06B008E83D4 /* CDVHandleOpenURL.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95CF81AB9028C008C4574 /* CDVHandleOpenURL.h */; };
+		A3B082D41BB15CEA00D8DC35 /* CDVGestureHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = A3B082D21BB15CEA00D8DC35 /* CDVGestureHandler.h */; };
+		A3B082D51BB15CEA00D8DC35 /* CDVGestureHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = A3B082D31BB15CEA00D8DC35 /* CDVGestureHandler.m */; };
+		C0C01EB61E3911D50056E6CB /* Cordova.h in Headers */ = {isa = PBXBuildFile; fileRef = C0C01EB41E3911D50056E6CB /* Cordova.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EBB1E39131A0056E6CB /* CDV.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D0F1AB9029B008C4574 /* CDV.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EBC1E39131A0056E6CB /* CDVAppDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D101AB9029B008C4574 /* CDVAppDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EBD1E39131A0056E6CB /* CDVAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D121AB9029B008C4574 /* CDVAvailability.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EBE1E39131A0056E6CB /* CDVAvailabilityDeprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D131AB9029B008C4574 /* CDVAvailabilityDeprecated.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EBF1E39131A0056E6CB /* CDVCommandDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D141AB9029B008C4574 /* CDVCommandDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC01E39131A0056E6CB /* CDVCommandDelegateImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D151AB9029B008C4574 /* CDVCommandDelegateImpl.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC11E39131A0056E6CB /* CDVCommandQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D171AB9029B008C4574 /* CDVCommandQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC21E39131A0056E6CB /* CDVConfigParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D191AB9029B008C4574 /* CDVConfigParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC31E39131A0056E6CB /* CDVInvokedUrlCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D1B1AB9029B008C4574 /* CDVInvokedUrlCommand.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC41E39131A0056E6CB /* CDVPlugin+Resources.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D1D1AB9029B008C4574 /* CDVPlugin+Resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC51E39131A0056E6CB /* CDVPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D1F1AB9029B008C4574 /* CDVPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC61E39131A0056E6CB /* CDVPluginResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D211AB9029B008C4574 /* CDVPluginResult.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC71E39131A0056E6CB /* CDVScreenOrientationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D231AB9029B008C4574 /* CDVScreenOrientationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01EC81E39131A0056E6CB /* CDVTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D241AB9029B008C4574 /* CDVTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01ECB1E39131A0056E6CB /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D2A1AB9029B008C4574 /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01ECC1E39131A0056E6CB /* CDVWebViewEngineProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D2C1AB9029B008C4574 /* CDVWebViewEngineProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01ECD1E39131A0056E6CB /* CDVWhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D2D1AB9029B008C4574 /* CDVWhitelist.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01ECE1E39131A0056E6CB /* NSDictionary+CordovaPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D311AB9029B008C4574 /* NSDictionary+CordovaPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		C0C01ECF1E39131A0056E6CB /* NSMutableArray+QueueAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7ED95D331AB9029B008C4574 /* NSMutableArray+QueueAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		28BFF9121F355A4E00DDF01A /* CDVLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVLogger.h; sourceTree = "<group>"; };
+		28BFF9131F355A4E00DDF01A /* CDVLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVLogger.m; sourceTree = "<group>"; };
+		2F4D42BA23F218BA00501999 /* CDVURLSchemeHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVURLSchemeHandler.h; sourceTree = "<group>"; };
+		2F4D42BB23F218BA00501999 /* CDVURLSchemeHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CDVURLSchemeHandler.m; sourceTree = "<group>"; };
+		3093E2211B16D6A3003F381A /* CDVIntentAndNavigationFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVIntentAndNavigationFilter.h; sourceTree = "<group>"; };
+		3093E2221B16D6A3003F381A /* CDVIntentAndNavigationFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVIntentAndNavigationFilter.m; sourceTree = "<group>"; };
+		4E23F8F523E16E96006CD852 /* CDVWebViewProcessPoolFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVWebViewProcessPoolFactory.m; sourceTree = "<group>"; };
+		4E23F8F623E16E96006CD852 /* CDVWebViewUIDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWebViewUIDelegate.h; sourceTree = "<group>"; };
+		4E23F8F723E16E96006CD852 /* CDVWebViewUIDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVWebViewUIDelegate.m; sourceTree = "<group>"; };
+		4E23F8F823E16E96006CD852 /* CDVWebViewEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVWebViewEngine.m; sourceTree = "<group>"; };
+		4E23F8F923E16E96006CD852 /* CDVWebViewProcessPoolFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWebViewProcessPoolFactory.h; sourceTree = "<group>"; };
+		4E23F8FA23E16E96006CD852 /* CDVWebViewEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWebViewEngine.h; sourceTree = "<group>"; };
+		4E714D3223F535B500A321AF /* CDVLaunchScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVLaunchScreen.h; sourceTree = "<group>"; };
+		4E714D3423F535B500A321AF /* CDVLaunchScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVLaunchScreen.m; sourceTree = "<group>"; };
+		68A32D7114102E1C006B237C /* libCordova.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCordova.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		7ED95CF21AB9028C008C4574 /* CDVDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVDebug.h; sourceTree = "<group>"; };
+		7ED95CF31AB9028C008C4574 /* CDVJSON_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVJSON_private.h; sourceTree = "<group>"; };
+		7ED95CF41AB9028C008C4574 /* CDVJSON_private.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVJSON_private.m; sourceTree = "<group>"; };
+		7ED95CF51AB9028C008C4574 /* CDVPlugin+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CDVPlugin+Private.h"; sourceTree = "<group>"; };
+		7ED95CF81AB9028C008C4574 /* CDVHandleOpenURL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVHandleOpenURL.h; sourceTree = "<group>"; };
+		7ED95CF91AB9028C008C4574 /* CDVHandleOpenURL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVHandleOpenURL.m; sourceTree = "<group>"; };
+		7ED95D0F1AB9029B008C4574 /* CDV.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDV.h; sourceTree = "<group>"; };
+		7ED95D101AB9029B008C4574 /* CDVAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVAppDelegate.h; sourceTree = "<group>"; };
+		7ED95D111AB9029B008C4574 /* CDVAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVAppDelegate.m; sourceTree = "<group>"; };
+		7ED95D121AB9029B008C4574 /* CDVAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVAvailability.h; sourceTree = "<group>"; };
+		7ED95D131AB9029B008C4574 /* CDVAvailabilityDeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVAvailabilityDeprecated.h; sourceTree = "<group>"; };
+		7ED95D141AB9029B008C4574 /* CDVCommandDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandDelegate.h; sourceTree = "<group>"; };
+		7ED95D151AB9029B008C4574 /* CDVCommandDelegateImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandDelegateImpl.h; sourceTree = "<group>"; };
+		7ED95D161AB9029B008C4574 /* CDVCommandDelegateImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVCommandDelegateImpl.m; sourceTree = "<group>"; };
+		7ED95D171AB9029B008C4574 /* CDVCommandQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandQueue.h; sourceTree = "<group>"; };
+		7ED95D181AB9029B008C4574 /* CDVCommandQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVCommandQueue.m; sourceTree = "<group>"; };
+		7ED95D191AB9029B008C4574 /* CDVConfigParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVConfigParser.h; sourceTree = "<group>"; };
+		7ED95D1A1AB9029B008C4574 /* CDVConfigParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVConfigParser.m; sourceTree = "<group>"; };
+		7ED95D1B1AB9029B008C4574 /* CDVInvokedUrlCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVInvokedUrlCommand.h; sourceTree = "<group>"; };
+		7ED95D1C1AB9029B008C4574 /* CDVInvokedUrlCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVInvokedUrlCommand.m; sourceTree = "<group>"; };
+		7ED95D1D1AB9029B008C4574 /* CDVPlugin+Resources.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CDVPlugin+Resources.h"; sourceTree = "<group>"; };
+		7ED95D1E1AB9029B008C4574 /* CDVPlugin+Resources.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CDVPlugin+Resources.m"; sourceTree = "<group>"; };
+		7ED95D1F1AB9029B008C4574 /* CDVPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVPlugin.h; sourceTree = "<group>"; };
+		7ED95D201AB9029B008C4574 /* CDVPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVPlugin.m; sourceTree = "<group>"; };
+		7ED95D211AB9029B008C4574 /* CDVPluginResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVPluginResult.h; sourceTree = "<group>"; };
+		7ED95D221AB9029B008C4574 /* CDVPluginResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVPluginResult.m; sourceTree = "<group>"; };
+		7ED95D231AB9029B008C4574 /* CDVScreenOrientationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVScreenOrientationDelegate.h; sourceTree = "<group>"; };
+		7ED95D241AB9029B008C4574 /* CDVTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVTimer.h; sourceTree = "<group>"; };
+		7ED95D251AB9029B008C4574 /* CDVTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVTimer.m; sourceTree = "<group>"; };
+		7ED95D2A1AB9029B008C4574 /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVViewController.h; sourceTree = "<group>"; };
+		7ED95D2B1AB9029B008C4574 /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVViewController.m; sourceTree = "<group>"; };
+		7ED95D2C1AB9029B008C4574 /* CDVWebViewEngineProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWebViewEngineProtocol.h; sourceTree = "<group>"; };
+		7ED95D2D1AB9029B008C4574 /* CDVWhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWhitelist.h; sourceTree = "<group>"; };
+		7ED95D2E1AB9029B008C4574 /* CDVWhitelist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVWhitelist.m; sourceTree = "<group>"; };
+		7ED95D311AB9029B008C4574 /* NSDictionary+CordovaPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+CordovaPreferences.h"; sourceTree = "<group>"; };
+		7ED95D321AB9029B008C4574 /* NSDictionary+CordovaPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+CordovaPreferences.m"; sourceTree = "<group>"; };
+		7ED95D331AB9029B008C4574 /* NSMutableArray+QueueAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+QueueAdditions.h"; sourceTree = "<group>"; };
+		7ED95D341AB9029B008C4574 /* NSMutableArray+QueueAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+QueueAdditions.m"; sourceTree = "<group>"; };
+		A3B082D21BB15CEA00D8DC35 /* CDVGestureHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVGestureHandler.h; sourceTree = "<group>"; };
+		A3B082D31BB15CEA00D8DC35 /* CDVGestureHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVGestureHandler.m; sourceTree = "<group>"; };
+		AA747D9E0F9514B9006C5449 /* CordovaLib_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CordovaLib_Prefix.pch; sourceTree = SOURCE_ROOT; };
+		C0C01EB21E3911D50056E6CB /* Cordova.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cordova.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		C0C01EB41E3911D50056E6CB /* Cordova.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Cordova.h; sourceTree = "<group>"; };
+		C0C01EB51E3911D50056E6CB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		C0C01EAE1E3911D50056E6CB /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D2AAC07C0554694100DB518D /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		034768DFFF38A50411DB9C8B /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				68A32D7114102E1C006B237C /* libCordova.a */,
+				C0C01EB21E3911D50056E6CB /* Cordova.framework */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		0867D691FE84028FC02AAC07 = {
+			isa = PBXGroup;
+			children = (
+				7ED95D0E1AB9029B008C4574 /* Public */,
+				7ED95CF11AB9028C008C4574 /* Private */,
+				C0C01EB31E3911D50056E6CB /* Cordova */,
+				034768DFFF38A50411DB9C8B /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		28BFF9111F355A1D00DDF01A /* CDVLogger */ = {
+			isa = PBXGroup;
+			children = (
+				28BFF9121F355A4E00DDF01A /* CDVLogger.h */,
+				28BFF9131F355A4E00DDF01A /* CDVLogger.m */,
+			);
+			path = CDVLogger;
+			sourceTree = "<group>";
+		};
+		3093E2201B16D6A3003F381A /* CDVIntentAndNavigationFilter */ = {
+			isa = PBXGroup;
+			children = (
+				3093E2211B16D6A3003F381A /* CDVIntentAndNavigationFilter.h */,
+				3093E2221B16D6A3003F381A /* CDVIntentAndNavigationFilter.m */,
+			);
+			path = CDVIntentAndNavigationFilter;
+			sourceTree = "<group>";
+		};
+		4E23F8F423E16D30006CD852 /* CDVWebViewEngine */ = {
+			isa = PBXGroup;
+			children = (
+				4E23F8FA23E16E96006CD852 /* CDVWebViewEngine.h */,
+				4E23F8F823E16E96006CD852 /* CDVWebViewEngine.m */,
+				4E23F8F923E16E96006CD852 /* CDVWebViewProcessPoolFactory.h */,
+				4E23F8F523E16E96006CD852 /* CDVWebViewProcessPoolFactory.m */,
+				4E23F8F623E16E96006CD852 /* CDVWebViewUIDelegate.h */,
+				4E23F8F723E16E96006CD852 /* CDVWebViewUIDelegate.m */,
+			);
+			path = CDVWebViewEngine;
+			sourceTree = "<group>";
+		};
+		4E714D3123F5356700A321AF /* CDVLaunchScreen */ = {
+			isa = PBXGroup;
+			children = (
+				4E714D3223F535B500A321AF /* CDVLaunchScreen.h */,
+				4E714D3423F535B500A321AF /* CDVLaunchScreen.m */,
+			);
+			path = CDVLaunchScreen;
+			sourceTree = "<group>";
+		};
+		7ED95CF11AB9028C008C4574 /* Private */ = {
+			isa = PBXGroup;
+			children = (
+				AA747D9E0F9514B9006C5449 /* CordovaLib_Prefix.pch */,
+				7ED95CF21AB9028C008C4574 /* CDVDebug.h */,
+				7ED95CF31AB9028C008C4574 /* CDVJSON_private.h */,
+				7ED95CF41AB9028C008C4574 /* CDVJSON_private.m */,
+				7ED95CF51AB9028C008C4574 /* CDVPlugin+Private.h */,
+				7ED95CF61AB9028C008C4574 /* Plugins */,
+			);
+			name = Private;
+			path = Classes/Private;
+			sourceTree = "<group>";
+		};
+		7ED95CF61AB9028C008C4574 /* Plugins */ = {
+			isa = PBXGroup;
+			children = (
+				4E714D3123F5356700A321AF /* CDVLaunchScreen */,
+				4E23F8F423E16D30006CD852 /* CDVWebViewEngine */,
+				28BFF9111F355A1D00DDF01A /* CDVLogger */,
+				A3B082D11BB15CEA00D8DC35 /* CDVGestureHandler */,
+				3093E2201B16D6A3003F381A /* CDVIntentAndNavigationFilter */,
+				7ED95CF71AB9028C008C4574 /* CDVHandleOpenURL */,
+			);
+			path = Plugins;
+			sourceTree = "<group>";
+		};
+		7ED95CF71AB9028C008C4574 /* CDVHandleOpenURL */ = {
+			isa = PBXGroup;
+			children = (
+				7ED95CF81AB9028C008C4574 /* CDVHandleOpenURL.h */,
+				7ED95CF91AB9028C008C4574 /* CDVHandleOpenURL.m */,
+			);
+			path = CDVHandleOpenURL;
+			sourceTree = "<group>";
+		};
+		7ED95D0E1AB9029B008C4574 /* Public */ = {
+			isa = PBXGroup;
+			children = (
+				7ED95D0F1AB9029B008C4574 /* CDV.h */,
+				7ED95D101AB9029B008C4574 /* CDVAppDelegate.h */,
+				7ED95D111AB9029B008C4574 /* CDVAppDelegate.m */,
+				7ED95D121AB9029B008C4574 /* CDVAvailability.h */,
+				7ED95D131AB9029B008C4574 /* CDVAvailabilityDeprecated.h */,
+				7ED95D141AB9029B008C4574 /* CDVCommandDelegate.h */,
+				7ED95D151AB9029B008C4574 /* CDVCommandDelegateImpl.h */,
+				7ED95D161AB9029B008C4574 /* CDVCommandDelegateImpl.m */,
+				7ED95D171AB9029B008C4574 /* CDVCommandQueue.h */,
+				7ED95D181AB9029B008C4574 /* CDVCommandQueue.m */,
+				7ED95D191AB9029B008C4574 /* CDVConfigParser.h */,
+				7ED95D1A1AB9029B008C4574 /* CDVConfigParser.m */,
+				7ED95D1B1AB9029B008C4574 /* CDVInvokedUrlCommand.h */,
+				7ED95D1C1AB9029B008C4574 /* CDVInvokedUrlCommand.m */,
+				7ED95D1D1AB9029B008C4574 /* CDVPlugin+Resources.h */,
+				7ED95D1E1AB9029B008C4574 /* CDVPlugin+Resources.m */,
+				7ED95D1F1AB9029B008C4574 /* CDVPlugin.h */,
+				7ED95D201AB9029B008C4574 /* CDVPlugin.m */,
+				7ED95D211AB9029B008C4574 /* CDVPluginResult.h */,
+				7ED95D221AB9029B008C4574 /* CDVPluginResult.m */,
+				7ED95D231AB9029B008C4574 /* CDVScreenOrientationDelegate.h */,
+				7ED95D241AB9029B008C4574 /* CDVTimer.h */,
+				7ED95D251AB9029B008C4574 /* CDVTimer.m */,
+				7ED95D2A1AB9029B008C4574 /* CDVViewController.h */,
+				7ED95D2B1AB9029B008C4574 /* CDVViewController.m */,
+				7ED95D2C1AB9029B008C4574 /* CDVWebViewEngineProtocol.h */,
+				7ED95D2D1AB9029B008C4574 /* CDVWhitelist.h */,
+				7ED95D2E1AB9029B008C4574 /* CDVWhitelist.m */,
+				7ED95D311AB9029B008C4574 /* NSDictionary+CordovaPreferences.h */,
+				7ED95D321AB9029B008C4574 /* NSDictionary+CordovaPreferences.m */,
+				7ED95D331AB9029B008C4574 /* NSMutableArray+QueueAdditions.h */,
+				7ED95D341AB9029B008C4574 /* NSMutableArray+QueueAdditions.m */,
+				2F4D42BA23F218BA00501999 /* CDVURLSchemeHandler.h */,
+				2F4D42BB23F218BA00501999 /* CDVURLSchemeHandler.m */,
+			);
+			name = Public;
+			path = Classes/Public;
+			sourceTree = "<group>";
+		};
+		A3B082D11BB15CEA00D8DC35 /* CDVGestureHandler */ = {
+			isa = PBXGroup;
+			children = (
+				A3B082D21BB15CEA00D8DC35 /* CDVGestureHandler.h */,
+				A3B082D31BB15CEA00D8DC35 /* CDVGestureHandler.m */,
+			);
+			path = CDVGestureHandler;
+			sourceTree = "<group>";
+		};
+		C0C01EB31E3911D50056E6CB /* Cordova */ = {
+			isa = PBXGroup;
+			children = (
+				C0C01EB41E3911D50056E6CB /* Cordova.h */,
+				C0C01EB51E3911D50056E6CB /* Info.plist */,
+			);
+			path = Cordova;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+		C0C01EAF1E3911D50056E6CB /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				C0C01EB61E3911D50056E6CB /* Cordova.h in Headers */,
+				C0C01EBB1E39131A0056E6CB /* CDV.h in Headers */,
+				C0C01EBC1E39131A0056E6CB /* CDVAppDelegate.h in Headers */,
+				C0C01EBD1E39131A0056E6CB /* CDVAvailability.h in Headers */,
+				C0C01EBE1E39131A0056E6CB /* CDVAvailabilityDeprecated.h in Headers */,
+				C0C01EBF1E39131A0056E6CB /* CDVCommandDelegate.h in Headers */,
+				C0C01EC01E39131A0056E6CB /* CDVCommandDelegateImpl.h in Headers */,
+				C0C01EC11E39131A0056E6CB /* CDVCommandQueue.h in Headers */,
+				C0C01EC21E39131A0056E6CB /* CDVConfigParser.h in Headers */,
+				C0C01EC31E39131A0056E6CB /* CDVInvokedUrlCommand.h in Headers */,
+				C0C01EC41E39131A0056E6CB /* CDVPlugin+Resources.h in Headers */,
+				C0C01EC51E39131A0056E6CB /* CDVPlugin.h in Headers */,
+				C0C01EC61E39131A0056E6CB /* CDVPluginResult.h in Headers */,
+				C0C01EC71E39131A0056E6CB /* CDVScreenOrientationDelegate.h in Headers */,
+				C0C01EC81E39131A0056E6CB /* CDVTimer.h in Headers */,
+				C0C01ECB1E39131A0056E6CB /* CDVViewController.h in Headers */,
+				C0C01ECC1E39131A0056E6CB /* CDVWebViewEngineProtocol.h in Headers */,
+				C0C01ECD1E39131A0056E6CB /* CDVWhitelist.h in Headers */,
+				C0C01ECE1E39131A0056E6CB /* NSDictionary+CordovaPreferences.h in Headers */,
+				4E23F90323E17FFA006CD852 /* CDVWebViewUIDelegate.h in Headers */,
+				C0C01ECF1E39131A0056E6CB /* NSMutableArray+QueueAdditions.h in Headers */,
+				9052DE892150D06B008E83D4 /* CDVDebug.h in Headers */,
+				9052DE8A2150D06B008E83D4 /* CDVJSON_private.h in Headers */,
+				9052DE8B2150D06B008E83D4 /* CDVPlugin+Private.h in Headers */,
+				9052DE8C2150D06B008E83D4 /* CDVLogger.h in Headers */,
+				9052DE8D2150D06B008E83D4 /* CDVGestureHandler.h in Headers */,
+				9052DE8E2150D06B008E83D4 /* CDVIntentAndNavigationFilter.h in Headers */,
+				9052DE8F2150D06B008E83D4 /* CDVHandleOpenURL.h in Headers */,
+				2FCCEA18247E7366007276A8 /* CDVLaunchScreen.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D2AAC07A0554694100DB518D /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7ED95D351AB9029B008C4574 /* CDV.h in Headers */,
+				7ED95D361AB9029B008C4574 /* CDVAppDelegate.h in Headers */,
+				7ED95D381AB9029B008C4574 /* CDVAvailability.h in Headers */,
+				7ED95D391AB9029B008C4574 /* CDVAvailabilityDeprecated.h in Headers */,
+				7ED95D3A1AB9029B008C4574 /* CDVCommandDelegate.h in Headers */,
+				7ED95D3B1AB9029B008C4574 /* CDVCommandDelegateImpl.h in Headers */,
+				7ED95D3D1AB9029B008C4574 /* CDVCommandQueue.h in Headers */,
+				4E23F8FF23E16E96006CD852 /* CDVWebViewProcessPoolFactory.h in Headers */,
+				7ED95D3F1AB9029B008C4574 /* CDVConfigParser.h in Headers */,
+				2F4D42BC23F218BA00501999 /* CDVURLSchemeHandler.h in Headers */,
+				7ED95D411AB9029B008C4574 /* CDVInvokedUrlCommand.h in Headers */,
+				7ED95D431AB9029B008C4574 /* CDVPlugin+Resources.h in Headers */,
+				7ED95D451AB9029B008C4574 /* CDVPlugin.h in Headers */,
+				7ED95D471AB9029B008C4574 /* CDVPluginResult.h in Headers */,
+				7ED95D491AB9029B008C4574 /* CDVScreenOrientationDelegate.h in Headers */,
+				4E23F8FC23E16E96006CD852 /* CDVWebViewUIDelegate.h in Headers */,
+				7ED95D4A1AB9029B008C4574 /* CDVTimer.h in Headers */,
+				7ED95D501AB9029B008C4574 /* CDVViewController.h in Headers */,
+				7ED95D521AB9029B008C4574 /* CDVWebViewEngineProtocol.h in Headers */,
+				4E23F90023E16E96006CD852 /* CDVWebViewEngine.h in Headers */,
+				7ED95D531AB9029B008C4574 /* CDVWhitelist.h in Headers */,
+				7ED95D571AB9029B008C4574 /* NSDictionary+CordovaPreferences.h in Headers */,
+				7ED95D591AB9029B008C4574 /* NSMutableArray+QueueAdditions.h in Headers */,
+				7ED95D021AB9028C008C4574 /* CDVDebug.h in Headers */,
+				7ED95D031AB9028C008C4574 /* CDVJSON_private.h in Headers */,
+				7ED95D051AB9028C008C4574 /* CDVPlugin+Private.h in Headers */,
+				28BFF9141F355A4E00DDF01A /* CDVLogger.h in Headers */,
+				A3B082D41BB15CEA00D8DC35 /* CDVGestureHandler.h in Headers */,
+				3093E2231B16D6A3003F381A /* CDVIntentAndNavigationFilter.h in Headers */,
+				7E7F69B91ABA3692007546F4 /* CDVHandleOpenURL.h in Headers */,
+				4E714D3623F535B500A321AF /* CDVLaunchScreen.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+		C0C01EB11E3911D50056E6CB /* Cordova */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = C0C01EB91E3911D50056E6CB /* Build configuration list for PBXNativeTarget "Cordova" */;
+			buildPhases = (
+				C0C01EAD1E3911D50056E6CB /* Sources */,
+				C0C01EAE1E3911D50056E6CB /* Frameworks */,
+				C0C01EAF1E3911D50056E6CB /* Headers */,
+				CEDDBB5523948D4C00506451 /* ShellScript */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Cordova;
+			productName = Cordova;
+			productReference = C0C01EB21E3911D50056E6CB /* Cordova.framework */;
+			productType = "com.apple.product-type.framework";
+		};
+		D2AAC07D0554694100DB518D /* CordovaLib */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "CordovaLib" */;
+			buildPhases = (
+				D2AAC07A0554694100DB518D /* Headers */,
+				D2AAC07B0554694100DB518D /* Sources */,
+				D2AAC07C0554694100DB518D /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = CordovaLib;
+			productName = CordovaLib;
+			productReference = 68A32D7114102E1C006B237C /* libCordova.a */;
+			productType = "com.apple.product-type.library.static";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		0867D690FE84028FC02AAC07 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 1010;
+				TargetAttributes = {
+					C0C01EB11E3911D50056E6CB = {
+						CreatedOnToolsVersion = 10.1;
+						ProvisioningStyle = Automatic;
+					};
+					D2AAC07D0554694100DB518D = {
+						CreatedOnToolsVersion = 10.1;
+						ProvisioningStyle = Automatic;
+					};
+				};
+			};
+			buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CordovaLib" */;
+			compatibilityVersion = "Xcode 11.0";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 0867D691FE84028FC02AAC07;
+			productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				D2AAC07D0554694100DB518D /* CordovaLib */,
+				C0C01EB11E3911D50056E6CB /* Cordova */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		CEDDBB5523948D4C00506451 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+			);
+			outputFileListPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PROJECT_DIR}/../update_podspec.sh\" -s cordova\n";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		C0C01EAD1E3911D50056E6CB /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9052DE712150D040008E83D4 /* CDVAppDelegate.m in Sources */,
+				9052DE722150D040008E83D4 /* CDVCommandDelegateImpl.m in Sources */,
+				9052DE732150D040008E83D4 /* CDVCommandQueue.m in Sources */,
+				9052DE742150D040008E83D4 /* CDVConfigParser.m in Sources */,
+				9052DE752150D040008E83D4 /* CDVInvokedUrlCommand.m in Sources */,
+				9052DE762150D040008E83D4 /* CDVPlugin+Resources.m in Sources */,
+				9052DE772150D040008E83D4 /* CDVPlugin.m in Sources */,
+				9052DE782150D040008E83D4 /* CDVPluginResult.m in Sources */,
+				9052DE792150D040008E83D4 /* CDVTimer.m in Sources */,
+				9052DE7C2150D040008E83D4 /* CDVViewController.m in Sources */,
+				9052DE7D2150D040008E83D4 /* CDVWhitelist.m in Sources */,
+				9052DE7E2150D040008E83D4 /* NSDictionary+CordovaPreferences.m in Sources */,
+				9052DE7F2150D040008E83D4 /* NSMutableArray+QueueAdditions.m in Sources */,
+				9052DE802150D040008E83D4 /* CDVJSON_private.m in Sources */,
+				9052DE812150D040008E83D4 /* CDVLogger.m in Sources */,
+				9052DE822150D040008E83D4 /* CDVGestureHandler.m in Sources */,
+				9052DE832150D040008E83D4 /* CDVIntentAndNavigationFilter.m in Sources */,
+				9052DE842150D040008E83D4 /* CDVHandleOpenURL.m in Sources */,
+				2FCCEA17247E7366007276A8 /* CDVLaunchScreen.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		D2AAC07B0554694100DB518D /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				7ED95D371AB9029B008C4574 /* CDVAppDelegate.m in Sources */,
+				7ED95D3C1AB9029B008C4574 /* CDVCommandDelegateImpl.m in Sources */,
+				7ED95D3E1AB9029B008C4574 /* CDVCommandQueue.m in Sources */,
+				7ED95D401AB9029B008C4574 /* CDVConfigParser.m in Sources */,
+				7ED95D421AB9029B008C4574 /* CDVInvokedUrlCommand.m in Sources */,
+				7ED95D441AB9029B008C4574 /* CDVPlugin+Resources.m in Sources */,
+				2F4D42BD23F218BA00501999 /* CDVURLSchemeHandler.m in Sources */,
+				7ED95D461AB9029B008C4574 /* CDVPlugin.m in Sources */,
+				7ED95D481AB9029B008C4574 /* CDVPluginResult.m in Sources */,
+				7ED95D4B1AB9029B008C4574 /* CDVTimer.m in Sources */,
+				4E23F8FE23E16E96006CD852 /* CDVWebViewEngine.m in Sources */,
+				4E23F8FB23E16E96006CD852 /* CDVWebViewProcessPoolFactory.m in Sources */,
+				7ED95D511AB9029B008C4574 /* CDVViewController.m in Sources */,
+				7ED95D541AB9029B008C4574 /* CDVWhitelist.m in Sources */,
+				7ED95D581AB9029B008C4574 /* NSDictionary+CordovaPreferences.m in Sources */,
+				7ED95D5A1AB9029B008C4574 /* NSMutableArray+QueueAdditions.m in Sources */,
+				7ED95D041AB9028C008C4574 /* CDVJSON_private.m in Sources */,
+				4E23F8FD23E16E96006CD852 /* CDVWebViewUIDelegate.m in Sources */,
+				28BFF9151F355A4E00DDF01A /* CDVLogger.m in Sources */,
+				A3B082D51BB15CEA00D8DC35 /* CDVGestureHandler.m in Sources */,
+				3093E2241B16D6A3003F381A /* CDVIntentAndNavigationFilter.m in Sources */,
+				7ED95D071AB9028C008C4574 /* CDVHandleOpenURL.m in Sources */,
+				4E714D3823F535B500A321AF /* CDVLaunchScreen.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		1DEB921F08733DC00010E9CD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PUBLIC_HEADERS_FOLDER_PATH = include/Cordova;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		1DEB922008733DC00010E9CD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PUBLIC_HEADERS_FOLDER_PATH = include/Cordova;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+		1DEB922308733DC00010E9CD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = CordovaLib_Prefix.pch;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_NAME = Cordova;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+			};
+			name = Debug;
+		};
+		1DEB922408733DC00010E9CD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = CordovaLib_Prefix.pch;
+				GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_NAME = Cordova;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = YES;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		C0C01EB71E3911D50056E6CB /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEFINES_MODULE = YES;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				INFOPLIST_FILE = Cordova/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+					"@loader_path/Frameworks",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = org.apache.cordova.Cordova;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Debug;
+		};
+		C0C01EB81E3911D50056E6CB /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				DEFINES_MODULE = YES;
+				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				INFOPLIST_FILE = Cordova/Info.plist;
+				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+					"@loader_path/Frameworks",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = org.apache.cordova.Cordova;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VERSIONING_SYSTEM = "apple-generic";
+				VERSION_INFO_PREFIX = "";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "CordovaLib" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB921F08733DC00010E9CD /* Debug */,
+				1DEB922008733DC00010E9CD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CordovaLib" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB922308733DC00010E9CD /* Debug */,
+				1DEB922408733DC00010E9CD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C0C01EB91E3911D50056E6CB /* Build configuration list for PBXNativeTarget "Cordova" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C0C01EB71E3911D50056E6CB /* Debug */,
+				C0C01EB81E3911D50056E6CB /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}

+ 19 - 0
cordova/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/x.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>Cordova.xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>1</integer>
+		</dict>
+		<key>CordovaLib.xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>2</integer>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 22 - 0
cordova/platforms/ios/CordovaLib/CordovaLib_Prefix.pch

@@ -0,0 +1,22 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#ifdef __OBJC__
+    #import <Foundation/Foundation.h>
+#endif

+ 1 - 0
cordova/platforms/ios/CordovaLib/VERSION

@@ -0,0 +1 @@
+6.1.1

+ 2104 - 0
cordova/platforms/ios/CordovaLib/cordova.js

@@ -0,0 +1,2104 @@
+// Platform: ios
+// 538a985db128858c0a0eb4dd40fb9c8e5433fc94
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+;(function() {
+var PLATFORM_VERSION_BUILD_LABEL = '6.1.1';
+// file: src/scripts/require.js
+var require;
+var define;
+
+(function () {
+    var modules = {};
+    // Stack of moduleIds currently being built.
+    var requireStack = [];
+    // Map of module ID -> index into requireStack of modules currently being built.
+    var inProgressModules = {};
+    var SEPARATOR = '.';
+
+    function build (module) {
+        var factory = module.factory;
+        var localRequire = function (id) {
+            var resultantId = id;
+            // Its a relative path, so lop off the last portion and add the id (minus "./")
+            if (id.charAt(0) === '.') {
+                resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);
+            }
+            return require(resultantId);
+        };
+        module.exports = {};
+        delete module.factory;
+        factory(localRequire, module.exports, module);
+        return module.exports;
+    }
+
+    require = function (id) {
+        if (!modules[id]) {
+            throw new Error('module ' + id + ' not found');
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw new Error('Cycle in require graph: ' + cycle);
+        }
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
+    };
+
+    define = function (id, factory) {
+        if (Object.prototype.hasOwnProperty.call(modules, id)) {
+            throw new Error('module ' + id + ' already defined');
+        }
+
+        modules[id] = {
+            id: id,
+            factory: factory
+        };
+    };
+
+    define.remove = function (id) {
+        delete modules[id];
+    };
+
+    define.moduleMap = modules;
+})();
+
+// Export for use in node
+if (typeof module === 'object' && typeof require === 'function') {
+    module.exports.require = require;
+    module.exports.define = define;
+}
+
+// file: src/cordova.js
+define("cordova", function(require, exports, module) {
+
+// Workaround for Windows 10 in hosted environment case
+// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object
+if (window.cordova && !(window.cordova instanceof HTMLElement)) {
+    throw new Error('cordova already defined');
+}
+
+var channel = require('cordova/channel');
+var platform = require('cordova/platform');
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {};
+var windowEventHandlers = {};
+
+document.addEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof documentEventHandlers[e] !== 'undefined') {
+        documentEventHandlers[e].subscribe(handler);
+    } else {
+        m_document_addEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.addEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof windowEventHandlers[e] !== 'undefined') {
+        windowEventHandlers[e].subscribe(handler);
+    } else {
+        m_window_addEventListener.call(window, evt, handler, capture);
+    }
+};
+
+document.removeEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof documentEventHandlers[e] !== 'undefined') {
+        documentEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_document_removeEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.removeEventListener = function (evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof windowEventHandlers[e] !== 'undefined') {
+        windowEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_window_removeEventListener.call(window, evt, handler, capture);
+    }
+};
+
+function createEvent (type, data) {
+    var event = document.createEvent('Events');
+    event.initEvent(type, false, false);
+    if (data) {
+        for (var i in data) {
+            if (Object.prototype.hasOwnProperty.call(data, i)) {
+                event[i] = data[i];
+            }
+        }
+    }
+    return event;
+}
+
+var cordova = {
+    define: define,
+    require: require,
+    version: PLATFORM_VERSION_BUILD_LABEL,
+    platformVersion: PLATFORM_VERSION_BUILD_LABEL,
+    platformId: platform.id,
+
+    /**
+     * Methods to add/remove your own addEventListener hijacking on document + window.
+     */
+    addWindowEventHandler: function (event) {
+        return (windowEventHandlers[event] = channel.create(event));
+    },
+    addStickyDocumentEventHandler: function (event) {
+        return (documentEventHandlers[event] = channel.createSticky(event));
+    },
+    addDocumentEventHandler: function (event) {
+        return (documentEventHandlers[event] = channel.create(event));
+    },
+    removeWindowEventHandler: function (event) {
+        delete windowEventHandlers[event];
+    },
+    removeDocumentEventHandler: function (event) {
+        delete documentEventHandlers[event];
+    },
+
+    /**
+     * Retrieve original event handlers that were replaced by Cordova
+     *
+     * @return object
+     */
+    getOriginalHandlers: function () {
+        return {
+            document: {
+                addEventListener: m_document_addEventListener,
+                removeEventListener: m_document_removeEventListener
+            },
+            window: {
+                addEventListener: m_window_addEventListener,
+                removeEventListener: m_window_removeEventListener
+            }
+        };
+    },
+
+    /**
+     * Method to fire event from native code
+     * bNoDetach is required for events which cause an exception which needs to be caught in native code
+     */
+    fireDocumentEvent: function (type, data, bNoDetach) {
+        var evt = createEvent(type, data);
+        if (typeof documentEventHandlers[type] !== 'undefined') {
+            if (bNoDetach) {
+                documentEventHandlers[type].fire(evt);
+            } else {
+                setTimeout(function () {
+                    // Fire deviceready on listeners that were registered before cordova.js was loaded.
+                    if (type === 'deviceready') {
+                        document.dispatchEvent(evt);
+                    }
+                    documentEventHandlers[type].fire(evt);
+                }, 0);
+            }
+        } else {
+            document.dispatchEvent(evt);
+        }
+    },
+
+    fireWindowEvent: function (type, data) {
+        var evt = createEvent(type, data);
+        if (typeof windowEventHandlers[type] !== 'undefined') {
+            setTimeout(function () {
+                windowEventHandlers[type].fire(evt);
+            }, 0);
+        } else {
+            window.dispatchEvent(evt);
+        }
+    },
+
+    /**
+     * Plugin callback mechanism.
+     */
+    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+    callbackId: Math.floor(Math.random() * 2000000000),
+    callbacks: {},
+    callbackStatus: {
+        NO_RESULT: 0,
+        OK: 1,
+        CLASS_NOT_FOUND_EXCEPTION: 2,
+        ILLEGAL_ACCESS_EXCEPTION: 3,
+        INSTANTIATION_EXCEPTION: 4,
+        MALFORMED_URL_EXCEPTION: 5,
+        IO_EXCEPTION: 6,
+        INVALID_ACTION: 7,
+        JSON_EXCEPTION: 8,
+        ERROR: 9
+    },
+
+    /**
+     * Called by native code when returning successful result from an action.
+     */
+    callbackSuccess: function (callbackId, args) {
+        cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+    },
+
+    /**
+     * Called by native code when returning error result from an action.
+     */
+    callbackError: function (callbackId, args) {
+        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+        // Derive success from status.
+        cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+    },
+
+    /**
+     * Called by native code when returning the result from an action.
+     */
+    callbackFromNative: function (callbackId, isSuccess, status, args, keepCallback) {
+        try {
+            var callback = cordova.callbacks[callbackId];
+            if (callback) {
+                if (isSuccess && status === cordova.callbackStatus.OK) {
+                    callback.success && callback.success.apply(null, args);
+                } else if (!isSuccess) {
+                    callback.fail && callback.fail.apply(null, args);
+                }
+                /*
+                else
+                    Note, this case is intentionally not caught.
+                    this can happen if isSuccess is true, but callbackStatus is NO_RESULT
+                    which is used to remove a callback from the list without calling the callbacks
+                    typically keepCallback is false in this case
+                */
+                // Clear callback if not expecting any more results
+                if (!keepCallback) {
+                    delete cordova.callbacks[callbackId];
+                }
+            }
+        } catch (err) {
+            var msg = 'Error in ' + (isSuccess ? 'Success' : 'Error') + ' callbackId: ' + callbackId + ' : ' + err;
+            cordova.fireWindowEvent('cordovacallbackerror', { message: msg, error: err });
+            throw err;
+        }
+    },
+
+    addConstructor: function (func) {
+        channel.onCordovaReady.subscribe(function () {
+            try {
+                func();
+            } catch (e) {
+                console.log('Failed to run constructor: ' + e);
+            }
+        });
+    }
+};
+
+module.exports = cordova;
+
+});
+
+// file: src/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+    A: 'Array',
+    D: 'Date',
+    N: 'Number',
+    S: 'String',
+    F: 'Function',
+    O: 'Object'
+};
+
+function extractParamName (callee, argIndex) {
+    return (/\(\s*([^)]*?)\s*\)/).exec(callee)[1].split(/\s*,\s*/)[argIndex];
+}
+
+/**
+ * Checks the given arguments' types and throws if they are not as expected.
+ *
+ * `spec` is a string where each character stands for the required type of the
+ * argument at the same position. In other words: the character at `spec[i]`
+ * specifies the required type for `args[i]`. The characters in `spec` are the
+ * first letter of the required type's name. The supported types are:
+ *
+ *     Array, Date, Number, String, Function, Object
+ *
+ * Lowercase characters specify arguments that must not be `null` or `undefined`
+ * while uppercase characters allow those values to be passed.
+ *
+ * Finally, `*` can be used to allow any type at the corresponding position.
+ *
+ * @example
+ * function foo (arr, opts) {
+ *     // require `arr` to be an Array and `opts` an Object, null or undefined
+ *     checkArgs('aO', 'my.package.foo', arguments);
+ *     // ...
+ * }
+ * @param {String} spec - the type specification for `args` as described above
+ * @param {String} functionName - full name of the callee.
+ * Used in the error message
+ * @param {Array|arguments} args - the arguments to be checked against `spec`
+ * @param {Function} [opt_callee=args.callee] - the recipient of `args`.
+ * Used to extract parameter names for the error message
+ * @throws {TypeError} if args do not satisfy spec
+ */
+function checkArgs (spec, functionName, args, opt_callee) {
+    if (!moduleExports.enableChecks) {
+        return;
+    }
+    var errMsg = null;
+    var typeName;
+    for (var i = 0; i < spec.length; ++i) {
+        var c = spec.charAt(i);
+        var cUpper = c.toUpperCase();
+        var arg = args[i];
+        // Asterix means allow anything.
+        if (c === '*') {
+            continue;
+        }
+        typeName = utils.typeName(arg);
+        if ((arg === null || arg === undefined) && c === cUpper) {
+            continue;
+        }
+        if (typeName !== typeMap[cUpper]) {
+            errMsg = 'Expected ' + typeMap[cUpper];
+            break;
+        }
+    }
+    if (errMsg) {
+        errMsg += ', but got ' + typeName + '.';
+        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+        // Don't log when running unit tests.
+        if (typeof jasmine === 'undefined') {
+            console.error(errMsg);
+        }
+        throw TypeError(errMsg);
+    }
+}
+
+function getValue (value, defaultValue) {
+    return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+});
+
+// file: src/common/base64.js
+define("cordova/base64", function(require, exports, module) {
+
+var base64 = exports;
+
+base64.fromArrayBuffer = function (arrayBuffer) {
+    var array = new Uint8Array(arrayBuffer);
+    return uint8ToBase64(array);
+};
+
+base64.toArrayBuffer = function (str) {
+    var decodedStr = atob(str);
+    var arrayBuffer = new ArrayBuffer(decodedStr.length);
+    var array = new Uint8Array(arrayBuffer);
+    for (var i = 0, len = decodedStr.length; i < len; i++) {
+        array[i] = decodedStr.charCodeAt(i);
+    }
+    return arrayBuffer;
+};
+
+// ------------------------------------------------------------------------------
+
+/* This code is based on the performance tests at http://jsperf.com/b64tests
+ * This 12-bit-at-a-time algorithm was the best performing version on all
+ * platforms tested.
+ */
+
+var b64_6bit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+var b64_12bit;
+
+var b64_12bitTable = function () {
+    b64_12bit = [];
+    for (var i = 0; i < 64; i++) {
+        for (var j = 0; j < 64; j++) {
+            b64_12bit[i * 64 + j] = b64_6bit[i] + b64_6bit[j];
+        }
+    }
+    b64_12bitTable = function () { return b64_12bit; };
+    return b64_12bit;
+};
+
+function uint8ToBase64 (rawData) {
+    var numBytes = rawData.byteLength;
+    var output = '';
+    var segment;
+    var table = b64_12bitTable();
+    for (var i = 0; i < numBytes - 2; i += 3) {
+        segment = (rawData[i] << 16) + (rawData[i + 1] << 8) + rawData[i + 2];
+        output += table[segment >> 12];
+        output += table[segment & 0xfff];
+    }
+    if (numBytes - i === 2) {
+        segment = (rawData[i] << 16) + (rawData[i + 1] << 8);
+        output += table[segment >> 12];
+        output += b64_6bit[(segment & 0xfff) >> 6];
+        output += '=';
+    } else if (numBytes - i === 1) {
+        segment = (rawData[i] << 16);
+        output += table[segment >> 12];
+        output += '==';
+    }
+    return output;
+}
+
+});
+
+// file: src/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each (objects, func, context) {
+    for (var prop in objects) {
+        if (Object.prototype.hasOwnProperty.call(objects, prop)) {
+            func.apply(context, [objects[prop], prop]);
+        }
+    }
+}
+
+function clobber (obj, key, value) {
+    var needsProperty = false;
+    try {
+        obj[key] = value;
+    } catch (e) {
+        needsProperty = true;
+    }
+    // Getters can only be overridden by getters.
+    if (needsProperty || obj[key] !== value) {
+        utils.defineGetter(obj, key, function () {
+            return value;
+        });
+    }
+}
+
+function assignOrWrapInDeprecateGetter (obj, key, value, message) {
+    if (message) {
+        utils.defineGetter(obj, key, function () {
+            console.log(message);
+            delete obj[key];
+            clobber(obj, key, value);
+            return value;
+        });
+    } else {
+        clobber(obj, key, value);
+    }
+}
+
+function include (parent, objects, clobber, merge) {
+    each(objects, function (obj, key) {
+        try {
+            var result = obj.path ? require(obj.path) : {};
+
+            if (clobber) {
+                // Clobber if it doesn't exist.
+                if (typeof parent[key] === 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else if (typeof obj.path !== 'undefined') {
+                    // If merging, merge properties onto parent, otherwise, clobber.
+                    if (merge) {
+                        recursiveMerge(parent[key], result);
+                    } else {
+                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                    }
+                }
+                result = parent[key];
+            } else {
+                // Overwrite if not currently defined.
+                if (typeof parent[key] === 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else {
+                    // Set result to what already exists, so we can build children into it if they exist.
+                    result = parent[key];
+                }
+            }
+
+            if (obj.children) {
+                include(result, obj.children, clobber, merge);
+            }
+        } catch (e) {
+            utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"');
+        }
+    });
+}
+
+/**
+ * Merge properties from one object onto another recursively.  Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge (target, src) {
+    for (var prop in src) {
+        if (Object.prototype.hasOwnProperty.call(src, prop)) {
+            if (target.prototype && target.prototype.constructor === target) {
+                // If the target object is a constructor override off prototype.
+                clobber(target.prototype, prop, src[prop]);
+            } else {
+                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+                    recursiveMerge(target[prop], src[prop]);
+                } else {
+                    clobber(target, prop, src[prop]);
+                }
+            }
+        }
+    }
+}
+
+exports.buildIntoButDoNotClobber = function (objects, target) {
+    include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function (objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function (objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+
+});
+
+// file: src/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+var nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady*              Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
+ * onDeviceReady*              User event fired to indicate that Cordova is ready
+ * onResume                    User event fired to indicate a start/resume lifecycle event
+ * onPause                     User event fired to indicate a pause lifecycle event
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ *      pause                 App has moved to background
+ *      resume                App has returned to foreground
+ *
+ * Listeners can be registered as:
+ *      document.addEventListener("deviceready", myDeviceReadyListener, false);
+ *      document.addEventListener("resume", myResumeListener, false);
+ *      document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ *      window.onload
+ *      window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type  String the channel name
+ */
+var Channel = function (type, sticky) {
+    this.type = type;
+    // Map of guid -> function.
+    this.handlers = {};
+    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+    this.state = sticky ? 1 : 0;
+    // Used in sticky mode to remember args passed to fire().
+    this.fireArgs = null;
+    // Used by onHasSubscribersChange to know if there are any listeners.
+    this.numHandlers = 0;
+    // Function that is called when the first listener is subscribed, or when
+    // the last listener is unsubscribed.
+    this.onHasSubscribersChange = null;
+};
+var channel = {
+    /**
+     * Calls the provided function only after all of the channels specified
+     * have been fired. All channels must be sticky channels.
+     */
+    join: function (h, c) {
+        var len = c.length;
+        var i = len;
+        var f = function () {
+            if (!(--i)) h();
+        };
+        for (var j = 0; j < len; j++) {
+            if (c[j].state === 0) {
+                throw Error('Can only use join with sticky channels.');
+            }
+            c[j].subscribe(f);
+        }
+        if (!len) h();
+    },
+
+    create: function (type) {
+        return (channel[type] = new Channel(type, false));
+    },
+    createSticky: function (type) {
+        return (channel[type] = new Channel(type, true));
+    },
+
+    /**
+     * cordova Channels that must fire before "deviceready" is fired.
+     */
+    deviceReadyChannelsArray: [],
+    deviceReadyChannelsMap: {},
+
+    /**
+     * Indicate that a feature needs to be initialized before it is ready to be used.
+     * This holds up Cordova's "deviceready" event until the feature has been initialized
+     * and Cordova.initComplete(feature) is called.
+     *
+     * @param feature {String}     The unique feature name
+     */
+    waitForInitialization: function (feature) {
+        if (feature) {
+            var c = channel[feature] || this.createSticky(feature);
+            this.deviceReadyChannelsMap[feature] = c;
+            this.deviceReadyChannelsArray.push(c);
+        }
+    },
+
+    /**
+     * Indicate that initialization code has completed and the feature is ready to be used.
+     *
+     * @param feature {String}     The unique feature name
+     */
+    initializationComplete: function (feature) {
+        var c = this.deviceReadyChannelsMap[feature];
+        if (c) {
+            c.fire();
+        }
+    }
+};
+
+function checkSubscriptionArgument (argument) {
+    if (typeof argument !== 'function' && typeof argument.handleEvent !== 'function') {
+        throw new Error(
+            'Must provide a function or an EventListener object ' +
+                'implementing the handleEvent interface.'
+        );
+    }
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function (eventListenerOrFunction, eventListener) {
+    checkSubscriptionArgument(eventListenerOrFunction);
+    var handleEvent, guid;
+
+    if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
+        // Received an EventListener object implementing the handleEvent interface
+        handleEvent = eventListenerOrFunction.handleEvent;
+        eventListener = eventListenerOrFunction;
+    } else {
+        // Received a function to handle event
+        handleEvent = eventListenerOrFunction;
+    }
+
+    if (this.state === 2) {
+        handleEvent.apply(eventListener || this, this.fireArgs);
+        return;
+    }
+
+    guid = eventListenerOrFunction.observer_guid;
+    if (typeof eventListener === 'object') {
+        handleEvent = utils.close(eventListener, handleEvent);
+    }
+
+    if (!guid) {
+        // First time any channel has seen this subscriber
+        guid = '' + nextGuid++;
+    }
+    handleEvent.observer_guid = guid;
+    eventListenerOrFunction.observer_guid = guid;
+
+    // Don't add the same handler more than once.
+    if (!this.handlers[guid]) {
+        this.handlers[guid] = handleEvent;
+        this.numHandlers++;
+        if (this.numHandlers === 1) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function (eventListenerOrFunction) {
+    checkSubscriptionArgument(eventListenerOrFunction);
+    var handleEvent, guid, handler;
+
+    if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
+        // Received an EventListener object implementing the handleEvent interface
+        handleEvent = eventListenerOrFunction.handleEvent;
+    } else {
+        // Received a function to handle event
+        handleEvent = eventListenerOrFunction;
+    }
+
+    guid = handleEvent.observer_guid;
+    handler = this.handlers[guid];
+    if (handler) {
+        delete this.handlers[guid];
+        this.numHandlers--;
+        if (this.numHandlers === 0) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function (e) {
+    var fireArgs = Array.prototype.slice.call(arguments);
+    // Apply stickiness.
+    if (this.state === 1) {
+        this.state = 2;
+        this.fireArgs = fireArgs;
+    }
+    if (this.numHandlers) {
+        // Copy the values first so that it is safe to modify it from within
+        // callbacks.
+        var toCall = [];
+        for (var item in this.handlers) {
+            toCall.push(this.handlers[item]);
+        }
+        for (var i = 0; i < toCall.length; ++i) {
+            toCall[i].apply(this, fireArgs);
+        }
+        if (this.state === 2 && this.numHandlers) {
+            this.numHandlers = 0;
+            this.handlers = {};
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+// FIXME remove this
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: ../cordova-ios/cordova-js-src/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Creates the exec bridge used to notify the native code of
+ * commands.
+ */
+var cordova = require('cordova');
+var utils = require('cordova/utils');
+var base64 = require('cordova/base64');
+
+function massageArgsJsToNative (args) {
+    if (!args || utils.typeName(args) !== 'Array') {
+        return args;
+    }
+    var ret = [];
+    args.forEach(function (arg, i) {
+        if (utils.typeName(arg) === 'ArrayBuffer') {
+            ret.push({
+                CDVType: 'ArrayBuffer',
+                data: base64.fromArrayBuffer(arg)
+            });
+        } else {
+            ret.push(arg);
+        }
+    });
+    return ret;
+}
+
+function massageMessageNativeToJs (message) {
+    if (message.CDVType === 'ArrayBuffer') {
+        var stringToArrayBuffer = function (str) {
+            var ret = new Uint8Array(str.length);
+            for (var i = 0; i < str.length; i++) {
+                ret[i] = str.charCodeAt(i);
+            }
+            return ret.buffer;
+        };
+        var base64ToArrayBuffer = function (b64) {
+            return stringToArrayBuffer(atob(b64)); // eslint-disable-line no-undef
+        };
+        message = base64ToArrayBuffer(message.data);
+    }
+    return message;
+}
+
+function convertMessageToArgsNativeToJs (message) {
+    var args = [];
+    if (!message || !Object.prototype.hasOwnProperty.call(message, 'CDVType')) {
+        args.push(message);
+    } else if (message.CDVType === 'MultiPart') {
+        message.messages.forEach(function (e) {
+            args.push(massageMessageNativeToJs(e));
+        });
+    } else {
+        args.push(massageMessageNativeToJs(message));
+    }
+    return args;
+}
+
+var iOSExec = function () {
+    var successCallback, failCallback, service, action, actionArgs;
+    var callbackId = null;
+    if (typeof arguments[0] !== 'string') {
+        // FORMAT ONE
+        successCallback = arguments[0];
+        failCallback = arguments[1];
+        service = arguments[2];
+        action = arguments[3];
+        actionArgs = arguments[4];
+
+        // Since we need to maintain backwards compatibility, we have to pass
+        // an invalid callbackId even if no callback was provided since plugins
+        // will be expecting it. The Cordova.exec() implementation allocates
+        // an invalid callbackId and passes it even if no callbacks were given.
+        callbackId = 'INVALID';
+    } else {
+   	    throw new Error('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' + // eslint-disable-line
+            'cordova.exec(null, null, \'Service\', \'action\', [ arg1, arg2 ]);');
+    }
+
+    // If actionArgs is not provided, default to an empty array
+    actionArgs = actionArgs || [];
+
+    // Register the callbacks and add the callbackId to the positional
+    // arguments if given.
+    if (successCallback || failCallback) {
+        callbackId = service + cordova.callbackId++;
+        cordova.callbacks[callbackId] =
+            { success: successCallback, fail: failCallback };
+    }
+
+    actionArgs = massageArgsJsToNative(actionArgs);
+
+    // CB-10133 DataClone DOM Exception 25 guard (fast function remover)
+    var command = [callbackId, service, action, JSON.parse(JSON.stringify(actionArgs))];
+    window.webkit.messageHandlers.cordova.postMessage(command);
+};
+
+iOSExec.nativeCallback = function (callbackId, status, message, keepCallback, debug) {
+    var success = status === 0 || status === 1;
+    var args = convertMessageToArgsNativeToJs(message);
+    Promise.resolve().then(function () {
+        cordova.callbackFromNative(callbackId, success, status, args, keepCallback); // eslint-disable-line
+    });
+};
+
+// for backwards compatibility
+iOSExec.nativeEvalAndFetch = function (func) {
+    try {
+        func();
+    } catch (e) {
+        console.log(e);
+    }
+};
+
+// Proxy the exec for bridge changes. See CB-10106
+
+function cordovaExec () {
+    var cexec = require('cordova/exec');
+    var cexec_valid = (typeof cexec.nativeFetchMessages === 'function') && (typeof cexec.nativeEvalAndFetch === 'function') && (typeof cexec.nativeCallback === 'function');
+    return (cexec_valid && execProxy !== cexec) ? cexec : iOSExec;
+}
+
+function execProxy () {
+    cordovaExec().apply(null, arguments);
+}
+
+execProxy.nativeFetchMessages = function () {
+    return cordovaExec().nativeFetchMessages.apply(null, arguments);
+};
+
+execProxy.nativeEvalAndFetch = function () {
+    return cordovaExec().nativeEvalAndFetch.apply(null, arguments);
+};
+
+execProxy.nativeCallback = function () {
+    return cordovaExec().nativeCallback.apply(null, arguments);
+};
+
+module.exports = execProxy;
+
+});
+
+// file: src/common/exec/proxy.js
+define("cordova/exec/proxy", function(require, exports, module) {
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+    // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+    add: function (id, proxyObj) {
+        console.log('adding proxy for ' + id);
+        CommandProxyMap[id] = proxyObj;
+        return proxyObj;
+    },
+
+    // cordova.commandProxy.remove("Accelerometer");
+    remove: function (id) {
+        var proxy = CommandProxyMap[id];
+        delete CommandProxyMap[id];
+        CommandProxyMap[id] = null;
+        return proxy;
+    },
+
+    get: function (service, action) {
+        return (CommandProxyMap[service] ? CommandProxyMap[service][action] : null);
+    }
+};
+
+});
+
+// file: src/common/init.js
+define("cordova/init", function(require, exports, module) {
+
+var channel = require('cordova/channel');
+var cordova = require('cordova');
+var modulemapper = require('cordova/modulemapper');
+var platform = require('cordova/platform');
+var pluginloader = require('cordova/pluginloader');
+
+var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
+
+function logUnfiredChannels (arr) {
+    for (var i = 0; i < arr.length; ++i) {
+        if (arr[i].state !== 2) {
+            console.log('Channel not fired: ' + arr[i].type);
+        }
+    }
+}
+
+window.setTimeout(function () {
+    if (channel.onDeviceReady.state !== 2) {
+        console.log('deviceready has not fired after 5 seconds.');
+        logUnfiredChannels(platformInitChannelsArray);
+        logUnfiredChannels(channel.deviceReadyChannelsArray);
+    }
+}, 5000);
+
+if (!window.console) {
+    window.console = {
+        log: function () {}
+    };
+}
+if (!window.console.warn) {
+    window.console.warn = function (msg) {
+        this.log('warn: ' + msg);
+    };
+}
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onActivated = cordova.addDocumentEventHandler('activated');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+// Listen for DOMContentLoaded and notify our channel subscribers.
+if (document.readyState === 'complete' || document.readyState === 'interactive') {
+    channel.onDOMContentLoaded.fire();
+} else {
+    document.addEventListener('DOMContentLoaded', function () {
+        channel.onDOMContentLoaded.fire();
+    }, false);
+}
+
+// _nativeReady is global variable that the native side can set
+// to signify that the native code is ready. It is a global since
+// it may be called before any cordova JS is ready.
+if (window._nativeReady) {
+    channel.onNativeReady.fire();
+}
+
+modulemapper.clobbers('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+// Call the platform-specific initialization.
+platform.bootstrap && platform.bootstrap();
+
+// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js.
+// The delay allows the attached modules to be defined before the plugin loader looks for them.
+setTimeout(function () {
+    pluginloader.load(function () {
+        channel.onPluginsReady.fire();
+    });
+}, 0);
+
+/**
+ * Create all cordova objects once native side is ready.
+ */
+channel.join(function () {
+    modulemapper.mapModules(window);
+
+    platform.initialize && platform.initialize();
+
+    // Fire event to notify that all objects are created
+    channel.onCordovaReady.fire();
+
+    // Fire onDeviceReady event once page has fully loaded, all
+    // constructors have run and cordova info has been received from native
+    // side.
+    channel.join(function () {
+        require('cordova').fireDocumentEvent('deviceready');
+    }, channel.deviceReadyChannelsArray);
+}, platformInitChannelsArray);
+
+});
+
+// file: src/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder');
+var moduleMap = define.moduleMap;
+var symbolList;
+var deprecationMap;
+
+exports.reset = function () {
+    symbolList = [];
+    deprecationMap = {};
+};
+
+function addEntry (strategy, moduleName, symbolPath, opt_deprecationMessage) {
+    if (!(moduleName in moduleMap)) {
+        throw new Error('Module ' + moduleName + ' does not exist.');
+    }
+    symbolList.push(strategy, moduleName, symbolPath);
+    if (opt_deprecationMessage) {
+        deprecationMap[symbolPath] = opt_deprecationMessage;
+    }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function (moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.runs = function (moduleName) {
+    addEntry('r', moduleName, null);
+};
+
+function prepareNamespace (symbolPath, context) {
+    if (!symbolPath) {
+        return context;
+    }
+    return symbolPath.split('.').reduce(function (cur, part) {
+        return (cur[part] = cur[part] || {});
+    }, context);
+}
+
+exports.mapModules = function (context) {
+    var origSymbols = {};
+    context.CDV_origSymbols = origSymbols;
+    for (var i = 0, len = symbolList.length; i < len; i += 3) {
+        var strategy = symbolList[i];
+        var moduleName = symbolList[i + 1];
+        var module = require(moduleName);
+        // <runs/>
+        if (strategy === 'r') {
+            continue;
+        }
+        var symbolPath = symbolList[i + 2];
+        var lastDot = symbolPath.lastIndexOf('.');
+        var namespace = symbolPath.substr(0, lastDot);
+        var lastName = symbolPath.substr(lastDot + 1);
+
+        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+        var parentObj = prepareNamespace(namespace, context);
+        var target = parentObj[lastName];
+
+        if (strategy === 'm' && target) {
+            builder.recursiveMerge(target, module);
+        } else if ((strategy === 'd' && !target) || (strategy !== 'd')) {
+            if (!(symbolPath in origSymbols)) {
+                origSymbols[symbolPath] = target;
+            }
+            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+        }
+    }
+};
+
+exports.getOriginalSymbol = function (context, symbolPath) {
+    var origSymbols = context.CDV_origSymbols;
+    if (origSymbols && (symbolPath in origSymbols)) {
+        return origSymbols[symbolPath];
+    }
+    var parts = symbolPath.split('.');
+    var obj = context;
+    for (var i = 0; i < parts.length; ++i) {
+        obj = obj && obj[parts[i]];
+    }
+    return obj;
+};
+
+exports.reset();
+
+});
+
+// file: ../cordova-ios/cordova-js-src/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+module.exports = {
+    id: 'ios',
+    bootstrap: function () {
+        // Attach the console polyfill that is iOS-only to window.console
+        // see the file under plugin/ios/console.js
+        require('cordova/modulemapper').clobbers('cordova/plugin/ios/console', 'window.console');
+
+        // Attach the wkwebkit utility to window.WkWebView
+        // see the file under plugin/ios/wkwebkit.js
+        require('cordova/modulemapper').clobbers('cordova/plugin/ios/wkwebkit', 'window.WkWebView');
+
+        // Attach the splashscreen utility to window.navigator.splashscreen
+        // see the file under plugin/ios/launchscreen.js
+        require('cordova/modulemapper').clobbers('cordova/plugin/ios/launchscreen', 'navigator.splashscreen');
+
+        require('cordova/channel').onNativeReady.fire();
+    }
+};
+
+});
+
+// file: ../cordova-ios/cordova-js-src/plugin/ios/console.js
+define("cordova/plugin/ios/console", function(require, exports, module) {
+
+// ------------------------------------------------------------------------------
+
+var logger = require('cordova/plugin/ios/logger');
+
+// ------------------------------------------------------------------------------
+// object that we're exporting
+// ------------------------------------------------------------------------------
+var console = module.exports;
+
+// ------------------------------------------------------------------------------
+// copy of the original console object
+// ------------------------------------------------------------------------------
+var WinConsole = window.console;
+
+// ------------------------------------------------------------------------------
+// whether to use the logger
+// ------------------------------------------------------------------------------
+var UseLogger = false;
+
+// ------------------------------------------------------------------------------
+// Timers
+// ------------------------------------------------------------------------------
+var Timers = {};
+
+// ------------------------------------------------------------------------------
+// used for unimplemented methods
+// ------------------------------------------------------------------------------
+function noop () {}
+
+// ------------------------------------------------------------------------------
+// used for unimplemented methods
+// ------------------------------------------------------------------------------
+console.useLogger = function (value) {
+    if (arguments.length) UseLogger = !!value;
+
+    if (UseLogger) {
+        if (logger.useConsole()) {
+            throw new Error('console and logger are too intertwingly');
+        }
+    }
+
+    return UseLogger;
+};
+
+// ------------------------------------------------------------------------------
+console.log = function () {
+    if (logger.useConsole()) return;
+    logger.log.apply(logger, [].slice.call(arguments));
+};
+
+// ------------------------------------------------------------------------------
+console.error = function () {
+    if (logger.useConsole()) return;
+    logger.error.apply(logger, [].slice.call(arguments));
+};
+
+// ------------------------------------------------------------------------------
+console.warn = function () {
+    if (logger.useConsole()) return;
+    logger.warn.apply(logger, [].slice.call(arguments));
+};
+
+// ------------------------------------------------------------------------------
+console.info = function () {
+    if (logger.useConsole()) return;
+    logger.info.apply(logger, [].slice.call(arguments));
+};
+
+// ------------------------------------------------------------------------------
+console.debug = function () {
+    if (logger.useConsole()) return;
+    logger.debug.apply(logger, [].slice.call(arguments));
+};
+
+// ------------------------------------------------------------------------------
+console.assert = function (expression) {
+    if (expression) return;
+
+    var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
+    console.log('ASSERT: ' + message);
+};
+
+// ------------------------------------------------------------------------------
+console.clear = function () {};
+
+// ------------------------------------------------------------------------------
+console.dir = function (object) {
+    console.log('%o', object);
+};
+
+// ------------------------------------------------------------------------------
+console.dirxml = function (node) {
+    console.log(node.innerHTML);
+};
+
+// ------------------------------------------------------------------------------
+console.trace = noop;
+
+// ------------------------------------------------------------------------------
+console.group = console.log;
+
+// ------------------------------------------------------------------------------
+console.groupCollapsed = console.log;
+
+// ------------------------------------------------------------------------------
+console.groupEnd = noop;
+
+// ------------------------------------------------------------------------------
+console.time = function (name) {
+    Timers[name] = new Date().valueOf();
+};
+
+// ------------------------------------------------------------------------------
+console.timeEnd = function (name) {
+    var timeStart = Timers[name];
+    if (!timeStart) {
+        console.warn('unknown timer: ' + name);
+        return;
+    }
+
+    var timeElapsed = new Date().valueOf() - timeStart;
+    console.log(name + ': ' + timeElapsed + 'ms');
+};
+
+// ------------------------------------------------------------------------------
+console.timeStamp = noop;
+
+// ------------------------------------------------------------------------------
+console.profile = noop;
+
+// ------------------------------------------------------------------------------
+console.profileEnd = noop;
+
+// ------------------------------------------------------------------------------
+console.count = noop;
+
+// ------------------------------------------------------------------------------
+console.exception = console.log;
+
+// ------------------------------------------------------------------------------
+console.table = function (data, columns) {
+    console.log('%o', data);
+};
+
+// ------------------------------------------------------------------------------
+// return a new function that calls both functions passed as args
+// ------------------------------------------------------------------------------
+function wrappedOrigCall (orgFunc, newFunc) {
+    return function () {
+        var args = [].slice.call(arguments);
+        try { orgFunc.apply(WinConsole, args); } catch (e) {}
+        try { newFunc.apply(console, args); } catch (e) {}
+    };
+}
+
+// ------------------------------------------------------------------------------
+// For every function that exists in the original console object, that
+// also exists in the new console object, wrap the new console method
+// with one that calls both
+// ------------------------------------------------------------------------------
+for (var key in console) {
+    if (typeof WinConsole[key] === 'function') {
+        console[key] = wrappedOrigCall(WinConsole[key], console[key]);
+    }
+}
+
+});
+
+// file: ../cordova-ios/cordova-js-src/plugin/ios/launchscreen.js
+define("cordova/plugin/ios/launchscreen", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+var launchscreen = {
+    show: function () {
+        exec(null, null, 'LaunchScreen', 'show', []);
+    },
+    hide: function () {
+        exec(null, null, 'LaunchScreen', 'hide', []);
+    }
+};
+
+module.exports = launchscreen;
+
+});
+
+// file: ../cordova-ios/cordova-js-src/plugin/ios/logger.js
+define("cordova/plugin/ios/logger", function(require, exports, module) {
+
+// ------------------------------------------------------------------------------
+// The logger module exports the following properties/functions:
+//
+// LOG                          - constant for the level LOG
+// ERROR                        - constant for the level ERROR
+// WARN                         - constant for the level WARN
+// INFO                         - constant for the level INFO
+// DEBUG                        - constant for the level DEBUG
+// logLevel()                   - returns current log level
+// logLevel(value)              - sets and returns a new log level
+// useConsole()                 - returns whether logger is using console
+// useConsole(value)            - sets and returns whether logger is using console
+// log(message,...)             - logs a message at level LOG
+// error(message,...)           - logs a message at level ERROR
+// warn(message,...)            - logs a message at level WARN
+// info(message,...)            - logs a message at level INFO
+// debug(message,...)           - logs a message at level DEBUG
+// logLevel(level,message,...)  - logs a message specified level
+//
+// ------------------------------------------------------------------------------
+
+var logger = exports;
+
+var exec = require('cordova/exec');
+
+var UseConsole = false;
+var UseLogger = true;
+var Queued = [];
+var DeviceReady = false;
+var CurrentLevel;
+
+var originalConsole = console;
+
+/**
+ * Logging levels
+ */
+
+var Levels = [
+    'LOG',
+    'ERROR',
+    'WARN',
+    'INFO',
+    'DEBUG'
+];
+
+/*
+ * add the logging levels to the logger object and
+ * to a separate levelsMap object for testing
+ */
+
+var LevelsMap = {};
+for (var i = 0; i < Levels.length; i++) {
+    var level = Levels[i];
+    LevelsMap[level] = i;
+    logger[level] = level;
+}
+
+CurrentLevel = LevelsMap.WARN;
+
+/**
+ * Getter/Setter for the logging level
+ *
+ * Returns the current logging level.
+ *
+ * When a value is passed, sets the logging level to that value.
+ * The values should be one of the following constants:
+ *    logger.LOG
+ *    logger.ERROR
+ *    logger.WARN
+ *    logger.INFO
+ *    logger.DEBUG
+ *
+ * The value used determines which messages get printed.  The logging
+ * values above are in order, and only messages logged at the logging
+ * level or above will actually be displayed to the user.  E.g., the
+ * default level is WARN, so only messages logged with LOG, ERROR, or
+ * WARN will be displayed; INFO and DEBUG messages will be ignored.
+ */
+logger.level = function (value) {
+    if (arguments.length) {
+        if (LevelsMap[value] === null) {
+            throw new Error('invalid logging level: ' + value);
+        }
+        CurrentLevel = LevelsMap[value];
+    }
+
+    return Levels[CurrentLevel];
+};
+
+/**
+ * Getter/Setter for the useConsole functionality
+ *
+ * When useConsole is true, the logger will log via the
+ * browser 'console' object.
+ */
+logger.useConsole = function (value) {
+    if (arguments.length) UseConsole = !!value;
+
+    if (UseConsole) {
+        if (typeof console === 'undefined') {
+            throw new Error('global console object is not defined');
+        }
+
+        if (typeof console.log !== 'function') {
+            throw new Error('global console object does not have a log function');
+        }
+
+        if (typeof console.useLogger === 'function') {
+            if (console.useLogger()) {
+                throw new Error('console and logger are too intertwingly');
+            }
+        }
+    }
+
+    return UseConsole;
+};
+
+/**
+ * Getter/Setter for the useLogger functionality
+ *
+ * When useLogger is true, the logger will log via the
+ * native Logger plugin.
+ */
+logger.useLogger = function (value) {
+    // Enforce boolean
+    if (arguments.length) UseLogger = !!value;
+    return UseLogger;
+};
+
+/**
+ * Logs a message at the LOG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.log = function (message) { logWithArgs('LOG', arguments); };
+
+/**
+ * Logs a message at the ERROR level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.error = function (message) { logWithArgs('ERROR', arguments); };
+
+/**
+ * Logs a message at the WARN level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.warn = function (message) { logWithArgs('WARN', arguments); };
+
+/**
+ * Logs a message at the INFO level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.info = function (message) { logWithArgs('INFO', arguments); };
+
+/**
+ * Logs a message at the DEBUG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.debug = function (message) { logWithArgs('DEBUG', arguments); };
+
+// log at the specified level with args
+function logWithArgs (level, args) {
+    args = [level].concat([].slice.call(args));
+    logger.logLevel.apply(logger, args);
+}
+
+// return the correct formatString for an object
+function formatStringForMessage (message) {
+    return (typeof message === 'string') ? '' : '%o';
+}
+
+/**
+ * Logs a message at the specified level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.logLevel = function (level /* , ... */) {
+    // format the message with the parameters
+    var formatArgs = [].slice.call(arguments, 1);
+    var fmtString = formatStringForMessage(formatArgs[0]);
+    if (fmtString.length > 0) {
+        formatArgs.unshift(fmtString); // add formatString
+    }
+
+    var message = logger.format.apply(logger.format, formatArgs);
+
+    if (LevelsMap[level] === null) {
+        throw new Error('invalid logging level: ' + level);
+    }
+
+    if (LevelsMap[level] > CurrentLevel) return;
+
+    // queue the message if not yet at deviceready
+    if (!DeviceReady && !UseConsole) {
+        Queued.push([level, message]);
+        return;
+    }
+
+    // Log using the native logger if that is enabled
+    if (UseLogger) {
+        exec(null, null, 'Console', 'logLevel', [level, message]);
+    }
+
+    // Log using the console if that is enabled
+    if (UseConsole) {
+        // make sure console is not using logger
+        if (console.useLogger()) {
+            throw new Error('console and logger are too intertwingly');
+        }
+
+        // log to the console
+        switch (level) {
+        case logger.LOG: originalConsole.log(message); break;
+        case logger.ERROR: originalConsole.log('ERROR: ' + message); break;
+        case logger.WARN: originalConsole.log('WARN: ' + message); break;
+        case logger.INFO: originalConsole.log('INFO: ' + message); break;
+        case logger.DEBUG: originalConsole.log('DEBUG: ' + message); break;
+        }
+    }
+};
+
+/**
+ * Formats a string and arguments following it ala console.log()
+ *
+ * Any remaining arguments will be appended to the formatted string.
+ *
+ * for rationale, see FireBug's Console API:
+ *    http://getfirebug.com/wiki/index.php/Console_API
+ */
+logger.format = function (formatString, args) {
+    return __format(arguments[0], [].slice.call(arguments, 1)).join(' ');
+};
+
+// ------------------------------------------------------------------------------
+/**
+ * Formats a string and arguments following it ala vsprintf()
+ *
+ * format chars:
+ *   %j - format arg as JSON
+ *   %o - format arg as JSON
+ *   %c - format arg as ''
+ *   %% - replace with '%'
+ * any other char following % will format it's
+ * arg via toString().
+ *
+ * Returns an array containing the formatted string and any remaining
+ * arguments.
+ */
+function __format (formatString, args) {
+    if (formatString === null || formatString === undefined) return [''];
+    if (arguments.length === 1) return [formatString.toString()];
+
+    if (typeof formatString !== 'string') { formatString = formatString.toString(); }
+
+    var pattern = /(.*?)%(.)(.*)/;
+    var rest = formatString;
+    var result = [];
+
+    while (args.length) {
+        var match = pattern.exec(rest);
+        if (!match) break;
+
+        var arg = args.shift();
+        rest = match[3];
+        result.push(match[1]);
+
+        if (match[2] === '%') {
+            result.push('%');
+            args.unshift(arg);
+            continue;
+        }
+
+        result.push(__formatted(arg, match[2]));
+    }
+
+    result.push(rest);
+
+    var remainingArgs = [].slice.call(args);
+    remainingArgs.unshift(result.join(''));
+    return remainingArgs;
+}
+
+function __formatted (object, formatChar) {
+    try {
+        switch (formatChar) {
+        case 'j':
+        case 'o': return JSON.stringify(object);
+        case 'c': return '';
+        }
+    } catch (e) {
+        return 'error JSON.stringify()ing argument: ' + e;
+    }
+
+    if ((object === null) || (object === undefined)) {
+        return Object.prototype.toString.call(object);
+    }
+
+    return object.toString();
+}
+
+// ------------------------------------------------------------------------------
+// when deviceready fires, log queued messages
+logger.__onDeviceReady = function () {
+    if (DeviceReady) return;
+
+    DeviceReady = true;
+
+    for (var i = 0; i < Queued.length; i++) {
+        var messageArgs = Queued[i];
+        logger.logLevel(messageArgs[0], messageArgs[1]);
+    }
+
+    Queued = null;
+};
+
+// add a deviceready event to log queued messages
+document.addEventListener('deviceready', logger.__onDeviceReady, false);
+
+});
+
+// file: ../cordova-ios/cordova-js-src/plugin/ios/wkwebkit.js
+define("cordova/plugin/ios/wkwebkit", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+var WkWebKit = {
+    allowsBackForwardNavigationGestures: function (allow) {
+        exec(null, null, 'CDVWebViewEngine', 'allowsBackForwardNavigationGestures', [allow]);
+    },
+    convertFilePath: function (path) {
+        if (!path || !window.CDV_ASSETS_URL) {
+            return path;
+        }
+        if (path.startsWith('/')) {
+            return window.CDV_ASSETS_URL + '/_app_file_' + path;
+        }
+        if (path.startsWith('file://')) {
+            return window.CDV_ASSETS_URL + path.replace('file://', '/_app_file_');
+        }
+        return path;
+    }
+};
+
+module.exports = WkWebKit;
+
+});
+
+// file: src/common/pluginloader.js
+define("cordova/pluginloader", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Helper function to inject a <script> tag.
+// Exported for testing.
+exports.injectScript = function (url, onload, onerror) {
+    var script = document.createElement('script');
+    // onload fires even when script fails loads with an error.
+    script.onload = onload;
+    // onerror fires for malformed URLs.
+    script.onerror = onerror;
+    script.src = url;
+    document.head.appendChild(script);
+};
+
+function injectIfNecessary (id, url, onload, onerror) {
+    onerror = onerror || onload;
+    if (id in define.moduleMap) {
+        onload();
+    } else {
+        exports.injectScript(url, function () {
+            if (id in define.moduleMap) {
+                onload();
+            } else {
+                onerror();
+            }
+        }, onerror);
+    }
+}
+
+function onScriptLoadingComplete (moduleList, finishPluginLoading) {
+    // Loop through all the plugins and then through their clobbers and merges.
+    for (var i = 0, module; (module = moduleList[i]); i++) {
+        if (module.clobbers && module.clobbers.length) {
+            for (var j = 0; j < module.clobbers.length; j++) {
+                modulemapper.clobbers(module.id, module.clobbers[j]);
+            }
+        }
+
+        if (module.merges && module.merges.length) {
+            for (var k = 0; k < module.merges.length; k++) {
+                modulemapper.merges(module.id, module.merges[k]);
+            }
+        }
+
+        // Finally, if runs is truthy we want to simply require() the module.
+        if (module.runs) {
+            modulemapper.runs(module.id);
+        }
+    }
+
+    finishPluginLoading();
+}
+
+// Handler for the cordova_plugins.js content.
+// See plugman's plugin_loader.js for the details of this object.
+// This function is only called if the really is a plugins array that isn't empty.
+// Otherwise the onerror response handler will just call finishPluginLoading().
+function handlePluginsObject (path, moduleList, finishPluginLoading) {
+    // Now inject the scripts.
+    var scriptCounter = moduleList.length;
+
+    if (!scriptCounter) {
+        finishPluginLoading();
+        return;
+    }
+    function scriptLoadedCallback () {
+        if (!--scriptCounter) {
+            onScriptLoadingComplete(moduleList, finishPluginLoading);
+        }
+    }
+
+    for (var i = 0; i < moduleList.length; i++) {
+        injectIfNecessary(moduleList[i].id, path + moduleList[i].file, scriptLoadedCallback);
+    }
+}
+
+function findCordovaPath () {
+    var path = null;
+    var scripts = document.getElementsByTagName('script');
+    var term = '/cordova.js';
+    for (var n = scripts.length - 1; n > -1; n--) {
+        var src = scripts[n].src.replace(/\?.*$/, ''); // Strip any query param (CB-6007).
+        if (src.indexOf(term) === (src.length - term.length)) {
+            path = src.substring(0, src.length - term.length) + '/';
+            break;
+        }
+    }
+    return path;
+}
+
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+exports.load = function (callback) {
+    var pathPrefix = findCordovaPath();
+    if (pathPrefix === null) {
+        console.log('Could not find cordova.js script tag. Plugin loading may fail.');
+        pathPrefix = '';
+    }
+    injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function () {
+        var moduleList = require('cordova/plugin_list');
+        handlePluginsObject(pathPrefix, moduleList, callback);
+    }, callback);
+};
+
+});
+
+// file: src/common/urlutil.js
+define("cordova/urlutil", function(require, exports, module) {
+
+/**
+ * For already absolute URLs, returns what is passed in.
+ * For relative URLs, converts them to absolute ones.
+ */
+exports.makeAbsolute = function makeAbsolute (url) {
+    var anchorEl = document.createElement('a');
+    anchorEl.href = url;
+    return anchorEl.href;
+};
+
+});
+
+// file: src/common/utils.js
+define("cordova/utils", function(require, exports, module) {
+
+var utils = exports;
+
+/**
+ * Defines a property getter / setter for obj[key].
+ */
+utils.defineGetterSetter = function (obj, key, getFunc, opt_setFunc) {
+    if (Object.defineProperty) {
+        var desc = {
+            get: getFunc,
+            configurable: true
+        };
+        if (opt_setFunc) {
+            desc.set = opt_setFunc;
+        }
+        Object.defineProperty(obj, key, desc);
+    } else {
+        obj.__defineGetter__(key, getFunc);
+        if (opt_setFunc) {
+            obj.__defineSetter__(key, opt_setFunc);
+        }
+    }
+};
+
+/**
+ * Defines a property getter for obj[key].
+ */
+utils.defineGetter = utils.defineGetterSetter;
+
+utils.arrayIndexOf = function (a, item) {
+    if (a.indexOf) {
+        return a.indexOf(item);
+    }
+    var len = a.length;
+    for (var i = 0; i < len; ++i) {
+        if (a[i] === item) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Returns whether the item was found in the array.
+ */
+utils.arrayRemove = function (a, item) {
+    var index = utils.arrayIndexOf(a, item);
+    if (index !== -1) {
+        a.splice(index, 1);
+    }
+    return index !== -1;
+};
+
+utils.typeName = function (val) {
+    return Object.prototype.toString.call(val).slice(8, -1);
+};
+
+/**
+ * Returns an indication of whether the argument is an array or not
+ */
+utils.isArray = Array.isArray ||
+                function (a) { return utils.typeName(a) === 'Array'; };
+
+/**
+ * Returns an indication of whether the argument is a Date or not
+ */
+utils.isDate = function (d) {
+    return (d instanceof Date);
+};
+
+/**
+ * Does a deep clone of the object.
+ */
+utils.clone = function (obj) {
+    if (!obj || typeof obj === 'function' || utils.isDate(obj) || typeof obj !== 'object') {
+        return obj;
+    }
+
+    var retVal, i;
+
+    if (utils.isArray(obj)) {
+        retVal = [];
+        for (i = 0; i < obj.length; ++i) {
+            retVal.push(utils.clone(obj[i]));
+        }
+        return retVal;
+    }
+
+    retVal = {};
+    for (i in obj) {
+        // 'unknown' type may be returned in custom protocol activation case on
+        // Windows Phone 8.1 causing "No such interface supported" exception on
+        // cloning (https://issues.apache.org/jira/browse/CB-11522)
+        // eslint-disable-next-line valid-typeof
+        if ((!(i in retVal) || retVal[i] !== obj[i]) && typeof obj[i] !== 'undefined' && typeof obj[i] !== 'unknown') {
+            retVal[i] = utils.clone(obj[i]);
+        }
+    }
+    return retVal;
+};
+
+/**
+ * Returns a wrapped version of the function
+ */
+utils.close = function (context, func, params) {
+    return function () {
+        var args = params || arguments;
+        return func.apply(context, args);
+    };
+};
+
+// ------------------------------------------------------------------------------
+function UUIDcreatePart (length) {
+    var uuidpart = '';
+    for (var i = 0; i < length; i++) {
+        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
+        if (uuidchar.length === 1) {
+            uuidchar = '0' + uuidchar;
+        }
+        uuidpart += uuidchar;
+    }
+    return uuidpart;
+}
+
+/**
+ * Create a UUID
+ */
+utils.createUUID = function () {
+    return UUIDcreatePart(4) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(6);
+};
+
+/**
+ * Extends a child object from a parent object using classical inheritance
+ * pattern.
+ */
+utils.extend = (function () {
+    // proxy used to establish prototype chain
+    var F = function () {};
+    // extend Child from Parent
+    return function (Child, Parent) {
+        F.prototype = Parent.prototype;
+        Child.prototype = new F();
+        Child.__super__ = Parent.prototype;
+        Child.prototype.constructor = Child;
+    };
+}());
+
+/**
+ * Alerts a message in any available way: alert or console.log.
+ */
+utils.alert = function (msg) {
+    if (window.alert) {
+        window.alert(msg);
+    } else if (console && console.log) {
+        console.log(msg);
+    }
+};
+
+});
+
+window.cordova = require('cordova');
+// file: src/scripts/bootstrap.js
+require('cordova/init');
+
+})();

+ 8 - 0
cordova/platforms/ios/Podfile

@@ -0,0 +1,8 @@
+# DO NOT MODIFY -- auto-generated by Apache Cordova
+
+platform :ios, '11.0'
+
+target '美天旺' do
+	project '美天旺.xcodeproj'
+
+end

+ 16 - 0
cordova/platforms/ios/frameworks.json

@@ -0,0 +1,16 @@
+{
+    "libz.tbd": 2,
+    "libsqlite3.0.tbd": 1,
+    "CoreTelephony.framework": 2,
+    "SystemConfiguration.framework": 2,
+    "Security.framework": 2,
+    "CFNetwork.framework": 2,
+    "Webkit.framework": 1,
+    "libc++.1.tbd": 1,
+    "CoreFoundation.framework": 1,
+    "Foundation.framework": 1,
+    "UIKit.framework": 1,
+    "AdSupport.framework": 1,
+    "UserNotifications.framework": 1,
+    "libresolv.tbd": 1
+}

+ 203 - 0
cordova/platforms/ios/ios.json

@@ -0,0 +1,203 @@
+{
+  "prepare_queue": {
+    "installed": [],
+    "uninstalled": []
+  },
+  "config_munge": {
+    "files": {
+      "*-Info.plist": {
+        "parents": {
+          "CFBundleURLTypes": [
+            {
+              "xml": "<array><dict><key>CFBundleURLSchemes</key><array><string>app</string></array></dict></array>",
+              "count": 1
+            },
+            {
+              "xml": "<array><dict><key>CFBundleURLName</key><string>weixin</string><key>CFBundleURLSchemes</key><array><string>wx1bb4342986c22b28</string></array></dict></array>",
+              "count": 1
+            }
+          ],
+          "LSApplicationQueriesSchemes": [
+            {
+              "xml": "<array><string>weixin</string><string>wechat</string><string>weixinULAPI</string></array>",
+              "count": 1
+            }
+          ],
+          "NSAppTransportSecurity": [
+            {
+              "xml": "<dict><key>NSAllowsArbitraryLoads</key><true /></dict>",
+              "count": 1
+            }
+          ],
+          "UIBackgroundModes": [
+            {
+              "xml": "<array><string>remote-notification</string></array>",
+              "count": 1
+            }
+          ]
+        }
+      },
+      "config.xml": {
+        "parents": {
+          "/*": [
+            {
+              "xml": "<feature name=\"Device\"><param name=\"ios-package\" value=\"CDVDevice\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"Wechat\"><param name=\"ios-package\" value=\"CDVWechat\" /><param name=\"onload\" value=\"true\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<preference name=\"WECHATAPPID\" value=\"wx1bb4342986c22b28\" />",
+              "count": 1
+            },
+            {
+              "xml": "<preference name=\"UNIVERSALLINK\" value=\"https://www.shotshock.shop/ios/\" />",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"JPushPlugin\"><param name=\"ios-package\" value=\"JPushPlugin\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<feature name=\"StatusBar\"><param name=\"ios-package\" value=\"CDVStatusBar\" /><param name=\"onload\" value=\"true\" /></feature>",
+              "count": 1
+            },
+            {
+              "xml": "<preference name=\"StatusBarOverlaysWebView\" value=\"true\" />",
+              "count": 1
+            },
+            {
+              "xml": "<preference name=\"StatusBarStyle\" value=\"lightcontent\" />",
+              "count": 1
+            }
+          ],
+          "/widget": []
+        }
+      },
+      "*-Debug.plist": {
+        "parents": {
+          "aps-environment": [
+            {
+              "xml": "<string>development</string>",
+              "count": 1
+            }
+          ]
+        }
+      },
+      "*-Release.plist": {
+        "parents": {
+          "aps-environment": [
+            {
+              "xml": "<string>production</string>",
+              "count": 1
+            }
+          ]
+        }
+      },
+      "*JPushConfig.plist": {
+        "parents": {
+          "Appkey": [
+            {
+              "xml": "<string>ab09fb9a832156e9c500ee68</string>",
+              "count": 1
+            }
+          ]
+        }
+      }
+    }
+  },
+  "installed_plugins": {
+    "cordova-plugin-customurlscheme": {
+      "URL_SCHEME": "app",
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-device": {
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-jcore": {
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-wechat": {
+      "WECHATAPPID": "wx1bb4342986c22b28",
+      "UNIVERSALLINK": "https://www.shotshock.shop/ios/",
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-whitelist": {
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "jpush-phonegap-plugin": {
+      "APP_KEY": "ab09fb9a832156e9c500ee68",
+      "CHANNEL": "developer-default",
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-fullscreen": {
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-statusbar": {
+      "PACKAGE_NAME": "com.shotshock.twong"
+    }
+  },
+  "dependent_plugins": {},
+  "modules": [
+    {
+      "id": "cordova-plugin-customurlscheme.LaunchMyApp",
+      "file": "plugins/cordova-plugin-customurlscheme/www/ios/LaunchMyApp.js",
+      "pluginId": "cordova-plugin-customurlscheme",
+      "clobbers": [
+        "window.plugins.launchmyapp"
+      ]
+    },
+    {
+      "id": "cordova-plugin-device.device",
+      "file": "plugins/cordova-plugin-device/www/device.js",
+      "pluginId": "cordova-plugin-device",
+      "clobbers": [
+        "device"
+      ]
+    },
+    {
+      "id": "cordova-plugin-wechat.Wechat",
+      "file": "plugins/cordova-plugin-wechat/www/wechat.js",
+      "pluginId": "cordova-plugin-wechat",
+      "clobbers": [
+        "Wechat"
+      ]
+    },
+    {
+      "id": "jpush-phonegap-plugin.JPushPlugin",
+      "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+      "pluginId": "jpush-phonegap-plugin",
+      "clobbers": [
+        "JPush"
+      ]
+    },
+    {
+      "id": "cordova-plugin-fullscreen.AndroidFullScreen",
+      "file": "plugins/cordova-plugin-fullscreen/www/AndroidFullScreen.js",
+      "pluginId": "cordova-plugin-fullscreen",
+      "clobbers": [
+        "AndroidFullScreen"
+      ]
+    },
+    {
+      "id": "cordova-plugin-statusbar.statusbar",
+      "file": "plugins/cordova-plugin-statusbar/www/statusbar.js",
+      "pluginId": "cordova-plugin-statusbar",
+      "clobbers": [
+        "window.StatusBar"
+      ]
+    }
+  ],
+  "plugin_metadata": {
+    "cordova-plugin-customurlscheme": "5.0.2",
+    "cordova-plugin-device": "2.0.3",
+    "cordova-plugin-jcore": "1.3.3",
+    "cordova-plugin-wechat": "3.0.0",
+    "cordova-plugin-whitelist": "1.3.4",
+    "jpush-phonegap-plugin": "3.7.6",
+    "cordova-plugin-fullscreen": "1.3.0",
+    "cordova-plugin-statusbar": "2.4.3"
+  }
+}

+ 20 - 0
cordova/platforms/ios/pods-debug.xcconfig

@@ -0,0 +1,20 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//  KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+// DO NOT MODIFY -- auto-generated by Apache Cordova

+ 20 - 0
cordova/platforms/ios/pods-release.xcconfig

@@ -0,0 +1,20 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//  KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+// DO NOT MODIFY -- auto-generated by Apache Cordova

+ 5 - 0
cordova/platforms/ios/pods.json

@@ -0,0 +1,5 @@
+{
+    "declarations": {},
+    "sources": {},
+    "libraries": {}
+}

+ 596 - 0
cordova/platforms/ios/美天旺.xcodeproj/project.pbxproj

@@ -0,0 +1,596 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 52;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		0207DA581B56EA530066E2B4 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0207DA571B56EA530066E2B4 /* Images.xcassets */; };
+		0605FDF6853B470980FFEBA3 /* JPushPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 647EEB681F2B4D9C9ABF0B52 /* JPushPlugin.m */; };
+		0D1C93094CB14F31A16602DA /* CDVDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F2CF5B35E1241B5A04D0C90 /* CDVDevice.m */; };
+		12C1234B9BB1451FBAF612BD /* libc++.1.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8FBA2A7B061A4DCDAAA61966 /* libc++.1.tbd */; };
+		15802058D28942759398B4B4 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 969C78309FFB44E4BF5ED50A /* libresolv.tbd */; settings = {ATTRIBUTES = (Weak, ); }; };
+		1D3623260D0F684500981E51 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* AppDelegate.m */; };
+		1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; };
+		1E2CA60A2CD54E529DFAF873 /* AppDelegate+Wechat.m in Sources */ = {isa = PBXBuildFile; fileRef = 92A41B443C4342F7BB0C317D /* AppDelegate+Wechat.m */; };
+		2FF06E6FA5444CF88FE78BF9 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BA7DBCB7F9E4A129426A36C /* SystemConfiguration.framework */; };
+		301BF552109A68D80062928A /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF535109A57CC0062928A /* libCordova.a */; settings = {ATTRIBUTES = (Required, ); }; };
+		302D95F114D2391D003F00A1 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 302D95EF14D2391D003F00A1 /* MainViewController.m */; };
+		302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 302D95F014D2391D003F00A1 /* MainViewController.xib */; };
+		559D20DFDD89408BA39E0BA8 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB22686FE8E1419AB2968277 /* UserNotifications.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		58E58C93FD9443B7BEDC600C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A26553BDD9A498C87F0051F /* Foundation.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		63CCAEFEECE9403B86A9F444 /* CDVStatusBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 88032390E7F24525876E7EA5 /* CDVStatusBar.m */; };
+		64901D0659854A8D9F7A3149 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CF582423AFF458AB62AD327 /* Security.framework */; };
+		67496FE971D44BACB7897A0E /* AppDelegate+JPush.m in Sources */ = {isa = PBXBuildFile; fileRef = A64B0F17C450427DAB86A53A /* AppDelegate+JPush.m */; };
+		6AFF5BF91D6E424B00AB3073 /* CDVLaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */; };
+		75F60E2EB84A42BDBB59D67F /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A304F2EBAA348DC85799DE8 /* CFNetwork.framework */; };
+		77F79F09A544472199CA5D57 /* CDVWechat.m in Sources */ = {isa = PBXBuildFile; fileRef = B6C1854537EF436EAFDADD32 /* CDVWechat.m */; };
+		8206F7D009A5445E8E49CA7D /* jpush-ios-3.3.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83E675356510447DB7B0170E /* jpush-ios-3.3.3.a */; };
+		8905C3C90B2E42E78C4A15A2 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13554308EDDB46F79B5A6259 /* CoreTelephony.framework */; };
+		9BAFF61F668E485DAC7782DE /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE552BFA359B4F54BB880E3E /* UIKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		B4FDE53EE5E0454FB8739856 /* libWeChatSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 61A9D3CA2D8149228414BCDE /* libWeChatSDK.a */; };
+		C8346C1C36A54812A9A72946 /* JPushConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = 94D1F885CDDD4DBB898B535D /* JPushConfig.plist */; };
+		D2B912B03F834BCAB152AAB1 /* jcore-ios-2.2.5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C02AD31B9F014104B663149E /* jcore-ios-2.2.5.a */; };
+		D38FD69CA9BD4D698F0BF808 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 821CABB37F3A43F2940D54A2 /* AdSupport.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		E2E2740B8D984349A5861FBD /* Webkit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF45E0A2D2BA4795992C9163 /* Webkit.framework */; };
+		E3AA3AE40CB9448FB46EDB8F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = AD7315985BE04AC2826B9DA8 /* libz.tbd */; };
+		EA6AA10E1AFD4211849F35A4 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6635FB5F08DC4046AE1611BB /* libsqlite3.0.tbd */; };
+		FEB9EE0A34BB4EA9977C8B47 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CAADBE3351646FBAF9D4CE3 /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		301BF534109A57CC0062928A /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = D2AAC07E0554694100DB518D;
+			remoteInfo = CordovaLib;
+		};
+		301BF550109A68C00062928A /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = D2AAC07D0554694100DB518D;
+			remoteInfo = CordovaLib;
+		};
+		907D8123214C687600058A10 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = C0C01EB21E3911D50056E6CB;
+			remoteInfo = Cordova;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+		0207DA571B56EA530066E2B4 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "美天旺/Images.xcassets"; sourceTree = SOURCE_ROOT; };
+		08FE6EBF97184BDDBE088281 /* CDVDevice.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVDevice.h; path = "cordova-plugin-device/CDVDevice.h"; sourceTree = "<group>"; };
+		0A304F2EBAA348DC85799DE8 /* CFNetwork.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
+		0A339903732243F8A6F468A8 /* JPUSHService.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = JPUSHService.h; path = "jpush-phonegap-plugin/JPUSHService.h"; sourceTree = "<group>"; };
+		0CAADBE3351646FBAF9D4CE3 /* CoreFoundation.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+		0CF582423AFF458AB62AD327 /* Security.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
+		12018477745242459E68F994 /* WechatAuthSDK.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = WechatAuthSDK.h; path = "cordova-plugin-wechat/WechatAuthSDK.h"; sourceTree = "<group>"; };
+		13554308EDDB46F79B5A6259 /* CoreTelephony.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
+		1A60CECDEA38432EA27D7A03 /* AppDelegate+Wechat.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "AppDelegate+Wechat.h"; path = "cordova-plugin-wechat/AppDelegate+Wechat.h"; sourceTree = "<group>"; };
+		1D3623240D0F684500981E51 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		1D3623250D0F684500981E51 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		1D6058910D05DD3D006BFB54 /* 美天旺.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "美天旺.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		2CAABF9D07A44D9C9B629614 /* WXApiObject.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = WXApiObject.h; path = "cordova-plugin-wechat/WXApiObject.h"; sourceTree = "<group>"; };
+		2F2CF5B35E1241B5A04D0C90 /* CDVDevice.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVDevice.m; path = "cordova-plugin-device/CDVDevice.m"; sourceTree = "<group>"; };
+		301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
+		301BF56E109A69640062928A /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = SOURCE_ROOT; };
+		302D95EE14D2391D003F00A1 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = "<group>"; };
+		302D95EF14D2391D003F00A1 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = "<group>"; };
+		302D95F014D2391D003F00A1 /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = "<group>"; };
+		3047A50F1AB8059700498E2A /* build-debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "build-debug.xcconfig"; path = "cordova/build-debug.xcconfig"; sourceTree = SOURCE_ROOT; };
+		3047A5101AB8059700498E2A /* build-release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "build-release.xcconfig"; path = "cordova/build-release.xcconfig"; sourceTree = SOURCE_ROOT; };
+		3047A5111AB8059700498E2A /* build.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = build.xcconfig; path = cordova/build.xcconfig; sourceTree = SOURCE_ROOT; };
+		32CA4F630368D1EE00C91783 /* 美天旺-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "美天旺-Prefix.pch"; sourceTree = "<group>"; };
+		42C4D76686FC4F33A4122887 /* JPushDefine.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = JPushDefine.h; path = "jpush-phonegap-plugin/JPushDefine.h"; sourceTree = "<group>"; };
+		4BA7DBCB7F9E4A129426A36C /* SystemConfiguration.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
+		61A9D3CA2D8149228414BCDE /* libWeChatSDK.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; name = libWeChatSDK.a; path = "美天旺/Plugins/cordova-plugin-wechat/libWeChatSDK.a"; sourceTree = "<group>"; };
+		647EEB681F2B4D9C9ABF0B52 /* JPushPlugin.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = JPushPlugin.m; path = "jpush-phonegap-plugin/JPushPlugin.m"; sourceTree = "<group>"; };
+		6635FB5F08DC4046AE1611BB /* libsqlite3.0.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
+		6677DA15BD1C4205AF98147D /* JPushPlugin.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = JPushPlugin.h; path = "jpush-phonegap-plugin/JPushPlugin.h"; sourceTree = "<group>"; };
+		6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = CDVLaunchScreen.storyboard; path = "美天旺/CDVLaunchScreen.storyboard"; sourceTree = SOURCE_ROOT; };
+		821CABB37F3A43F2940D54A2 /* AdSupport.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
+		83E675356510447DB7B0170E /* jpush-ios-3.3.3.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; name = "jpush-ios-3.3.3.a"; path = "美天旺/Plugins/jpush-phonegap-plugin/jpush-ios-3.3.3.a"; sourceTree = "<group>"; };
+		88032390E7F24525876E7EA5 /* CDVStatusBar.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVStatusBar.m; path = "cordova-plugin-statusbar/CDVStatusBar.m"; sourceTree = "<group>"; };
+		8A26553BDD9A498C87F0051F /* Foundation.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		8AF854D7C96D4CBABF731728 /* AppDelegate+JPush.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "AppDelegate+JPush.h"; path = "jpush-phonegap-plugin/AppDelegate+JPush.h"; sourceTree = "<group>"; };
+		8D1107310486CEB800E47090 /* 美天旺-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "美天旺-Info.plist"; path = "美天旺/美天旺-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = SOURCE_ROOT; };
+		8FBA2A7B061A4DCDAAA61966 /* libc++.1.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.1.tbd"; path = "usr/lib/libc++.1.tbd"; sourceTree = SDKROOT; };
+		92A41B443C4342F7BB0C317D /* AppDelegate+Wechat.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = "AppDelegate+Wechat.m"; path = "cordova-plugin-wechat/AppDelegate+Wechat.m"; sourceTree = "<group>"; };
+		94D1F885CDDD4DBB898B535D /* JPushConfig.plist */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = text.plist.xml; path = JPushConfig.plist; sourceTree = "<group>"; };
+		969C78309FFB44E4BF5ED50A /* libresolv.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
+		A64B0F17C450427DAB86A53A /* AppDelegate+JPush.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = "AppDelegate+JPush.m"; path = "jpush-phonegap-plugin/AppDelegate+JPush.m"; sourceTree = "<group>"; };
+		AD7315985BE04AC2826B9DA8 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
+		AF45E0A2D2BA4795992C9163 /* Webkit.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = Webkit.framework; path = System/Library/Frameworks/Webkit.framework; sourceTree = SDKROOT; };
+		B4BF51C0554344E98E5135C6 /* CDVStatusBar.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVStatusBar.h; path = "cordova-plugin-statusbar/CDVStatusBar.h"; sourceTree = "<group>"; };
+		B6C1854537EF436EAFDADD32 /* CDVWechat.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVWechat.m; path = "cordova-plugin-wechat/CDVWechat.m"; sourceTree = "<group>"; };
+		C02AD31B9F014104B663149E /* jcore-ios-2.2.5.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; name = "jcore-ios-2.2.5.a"; path = "美天旺/Plugins/cordova-plugin-jcore/jcore-ios-2.2.5.a"; sourceTree = "<group>"; };
+		CE552BFA359B4F54BB880E3E /* UIKit.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		E89776F7747D4496ACF1D820 /* WXApi.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = WXApi.h; path = "cordova-plugin-wechat/WXApi.h"; sourceTree = "<group>"; };
+		EB22686FE8E1419AB2968277 /* UserNotifications.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
+		EB87FDF31871DA8E0020F90C /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; name = www; path = ../../www; sourceTree = "<group>"; };
+		EB87FDF41871DAF40020F90C /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = ../../config.xml; sourceTree = "<group>"; };
+		ED33DF2A687741AEAF9F8254 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
+		F4B2976FF2734DD7B85D35C5 /* CDVWechat.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVWechat.h; path = "cordova-plugin-wechat/CDVWechat.h"; sourceTree = "<group>"; };
+		F840E1F0165FE0F500CFE078 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = "美天旺/config.xml"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		1D60588F0D05DD3D006BFB54 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				301BF552109A68D80062928A /* libCordova.a in Frameworks */,
+				D2B912B03F834BCAB152AAB1 /* jcore-ios-2.2.5.a in Frameworks */,
+				B4FDE53EE5E0454FB8739856 /* libWeChatSDK.a in Frameworks */,
+				E3AA3AE40CB9448FB46EDB8F /* libz.tbd in Frameworks */,
+				EA6AA10E1AFD4211849F35A4 /* libsqlite3.0.tbd in Frameworks */,
+				8905C3C90B2E42E78C4A15A2 /* CoreTelephony.framework in Frameworks */,
+				2FF06E6FA5444CF88FE78BF9 /* SystemConfiguration.framework in Frameworks */,
+				64901D0659854A8D9F7A3149 /* Security.framework in Frameworks */,
+				75F60E2EB84A42BDBB59D67F /* CFNetwork.framework in Frameworks */,
+				E2E2740B8D984349A5861FBD /* Webkit.framework in Frameworks */,
+				12C1234B9BB1451FBAF612BD /* libc++.1.tbd in Frameworks */,
+				8206F7D009A5445E8E49CA7D /* jpush-ios-3.3.3.a in Frameworks */,
+				FEB9EE0A34BB4EA9977C8B47 /* CoreFoundation.framework in Frameworks */,
+				58E58C93FD9443B7BEDC600C /* Foundation.framework in Frameworks */,
+				9BAFF61F668E485DAC7782DE /* UIKit.framework in Frameworks */,
+				D38FD69CA9BD4D698F0BF808 /* AdSupport.framework in Frameworks */,
+				559D20DFDD89408BA39E0BA8 /* UserNotifications.framework in Frameworks */,
+				15802058D28942759398B4B4 /* libresolv.tbd in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		080E96DDFE201D6D7F000001 /* Classes */ = {
+			isa = PBXGroup;
+			children = (
+				302D95EE14D2391D003F00A1 /* MainViewController.h */,
+				302D95EF14D2391D003F00A1 /* MainViewController.m */,
+				302D95F014D2391D003F00A1 /* MainViewController.xib */,
+				1D3623240D0F684500981E51 /* AppDelegate.h */,
+				1D3623250D0F684500981E51 /* AppDelegate.m */,
+			);
+			name = Classes;
+			path = "美天旺/Classes";
+			sourceTree = SOURCE_ROOT;
+		};
+		19C28FACFE9D520D11CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				1D6058910D05DD3D006BFB54 /* 美天旺.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
+			isa = PBXGroup;
+			children = (
+				EB87FDF41871DAF40020F90C /* config.xml */,
+				EB87FDF31871DA8E0020F90C /* www */,
+				EB87FDF11871DA420020F90C /* Staging */,
+				301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */,
+				080E96DDFE201D6D7F000001 /* Classes */,
+				307C750510C5A3420062BCA9 /* Plugins */,
+				29B97315FDCFA39411CA2CEA /* Other Sources */,
+				29B97317FDCFA39411CA2CEA /* Resources */,
+				29B97323FDCFA39411CA2CEA /* Frameworks */,
+				19C28FACFE9D520D11CA2CBB /* Products */,
+			);
+			name = CustomTemplate;
+			sourceTree = "<group>";
+		};
+		29B97315FDCFA39411CA2CEA /* Other Sources */ = {
+			isa = PBXGroup;
+			children = (
+				32CA4F630368D1EE00C91783 /* 美天旺-Prefix.pch */,
+				29B97316FDCFA39411CA2CEA /* main.m */,
+				ED33DF2A687741AEAF9F8254 /* Bridging-Header.h */,
+			);
+			name = "Other Sources";
+			path = "美天旺";
+			sourceTree = "<group>";
+		};
+		29B97317FDCFA39411CA2CEA /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				0207DA571B56EA530066E2B4 /* Images.xcassets */,
+				3047A50E1AB8057F00498E2A /* config */,
+				8D1107310486CEB800E47090 /* 美天旺-Info.plist */,
+				6AFF5BF81D6E424B00AB3073 /* CDVLaunchScreen.storyboard */,
+				94D1F885CDDD4DBB898B535D /* JPushConfig.plist */,
+			);
+			name = Resources;
+			path = "美天旺/Resources";
+			sourceTree = "<group>";
+		};
+		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				C02AD31B9F014104B663149E /* jcore-ios-2.2.5.a */,
+				61A9D3CA2D8149228414BCDE /* libWeChatSDK.a */,
+				AD7315985BE04AC2826B9DA8 /* libz.tbd */,
+				6635FB5F08DC4046AE1611BB /* libsqlite3.0.tbd */,
+				13554308EDDB46F79B5A6259 /* CoreTelephony.framework */,
+				4BA7DBCB7F9E4A129426A36C /* SystemConfiguration.framework */,
+				0CF582423AFF458AB62AD327 /* Security.framework */,
+				0A304F2EBAA348DC85799DE8 /* CFNetwork.framework */,
+				AF45E0A2D2BA4795992C9163 /* Webkit.framework */,
+				8FBA2A7B061A4DCDAAA61966 /* libc++.1.tbd */,
+				83E675356510447DB7B0170E /* jpush-ios-3.3.3.a */,
+				0CAADBE3351646FBAF9D4CE3 /* CoreFoundation.framework */,
+				8A26553BDD9A498C87F0051F /* Foundation.framework */,
+				CE552BFA359B4F54BB880E3E /* UIKit.framework */,
+				821CABB37F3A43F2940D54A2 /* AdSupport.framework */,
+				EB22686FE8E1419AB2968277 /* UserNotifications.framework */,
+				969C78309FFB44E4BF5ED50A /* libresolv.tbd */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		301BF52E109A57CC0062928A /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				301BF535109A57CC0062928A /* libCordova.a */,
+				907D8124214C687600058A10 /* Cordova.framework */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		3047A50E1AB8057F00498E2A /* config */ = {
+			isa = PBXGroup;
+			children = (
+				3047A50F1AB8059700498E2A /* build-debug.xcconfig */,
+				3047A5101AB8059700498E2A /* build-release.xcconfig */,
+				3047A5111AB8059700498E2A /* build.xcconfig */,
+			);
+			name = config;
+			sourceTree = "<group>";
+		};
+		307C750510C5A3420062BCA9 /* Plugins */ = {
+			isa = PBXGroup;
+			children = (
+				2F2CF5B35E1241B5A04D0C90 /* CDVDevice.m */,
+				08FE6EBF97184BDDBE088281 /* CDVDevice.h */,
+				B6C1854537EF436EAFDADD32 /* CDVWechat.m */,
+				92A41B443C4342F7BB0C317D /* AppDelegate+Wechat.m */,
+				F4B2976FF2734DD7B85D35C5 /* CDVWechat.h */,
+				1A60CECDEA38432EA27D7A03 /* AppDelegate+Wechat.h */,
+				E89776F7747D4496ACF1D820 /* WXApi.h */,
+				2CAABF9D07A44D9C9B629614 /* WXApiObject.h */,
+				12018477745242459E68F994 /* WechatAuthSDK.h */,
+				647EEB681F2B4D9C9ABF0B52 /* JPushPlugin.m */,
+				A64B0F17C450427DAB86A53A /* AppDelegate+JPush.m */,
+				42C4D76686FC4F33A4122887 /* JPushDefine.h */,
+				6677DA15BD1C4205AF98147D /* JPushPlugin.h */,
+				8AF854D7C96D4CBABF731728 /* AppDelegate+JPush.h */,
+				0A339903732243F8A6F468A8 /* JPUSHService.h */,
+				88032390E7F24525876E7EA5 /* CDVStatusBar.m */,
+				B4BF51C0554344E98E5135C6 /* CDVStatusBar.h */,
+			);
+			name = Plugins;
+			path = "美天旺/Plugins";
+			sourceTree = SOURCE_ROOT;
+		};
+		EB87FDF11871DA420020F90C /* Staging */ = {
+			isa = PBXGroup;
+			children = (
+				F840E1F0165FE0F500CFE078 /* config.xml */,
+				301BF56E109A69640062928A /* www */,
+			);
+			name = Staging;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		1D6058900D05DD3D006BFB54 /* 美天旺 */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "美天旺" */;
+			buildPhases = (
+				304B58A110DAC018002A0835 /* Copy www directory */,
+				1D60588D0D05DD3D006BFB54 /* Resources */,
+				1D60588E0D05DD3D006BFB54 /* Sources */,
+				1D60588F0D05DD3D006BFB54 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				301BF551109A68C00062928A /* PBXTargetDependency */,
+			);
+			name = "美天旺";
+			productName = "美天旺";
+			productReference = 1D6058910D05DD3D006BFB54 /* 美天旺.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		29B97313FDCFA39411CA2CEA /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 1130;
+			};
+			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "美天旺" */;
+			compatibilityVersion = "Xcode 11.0";
+			developmentRegion = en;
+			hasScannedForEncodings = 1;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
+			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = 301BF52E109A57CC0062928A /* Products */;
+					ProjectRef = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
+				},
+			);
+			projectRoot = "";
+			targets = (
+				1D6058900D05DD3D006BFB54 /* 美天旺 */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+		301BF535109A57CC0062928A /* libCordova.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libCordova.a;
+			remoteRef = 301BF534109A57CC0062928A /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		907D8124214C687600058A10 /* Cordova.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = Cordova.framework;
+			remoteRef = 907D8123214C687600058A10 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		1D60588D0D05DD3D006BFB54 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */,
+				0207DA581B56EA530066E2B4 /* Images.xcassets in Resources */,
+				6AFF5BF91D6E424B00AB3073 /* CDVLaunchScreen.storyboard in Resources */,
+				C8346C1C36A54812A9A72946 /* JPushConfig.plist in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		304B58A110DAC018002A0835 /* Copy www directory */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Copy www directory";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"$SRCROOT/美天旺/Scripts/copy-www-build-step.sh\"";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		1D60588E0D05DD3D006BFB54 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				1D60589B0D05DD56006BFB54 /* main.m in Sources */,
+				1D3623260D0F684500981E51 /* AppDelegate.m in Sources */,
+				302D95F114D2391D003F00A1 /* MainViewController.m in Sources */,
+				0D1C93094CB14F31A16602DA /* CDVDevice.m in Sources */,
+				77F79F09A544472199CA5D57 /* CDVWechat.m in Sources */,
+				1E2CA60A2CD54E529DFAF873 /* AppDelegate+Wechat.m in Sources */,
+				0605FDF6853B470980FFEBA3 /* JPushPlugin.m in Sources */,
+				67496FE971D44BACB7897A0E /* AppDelegate+JPush.m in Sources */,
+				63CCAEFEECE9403B86A9F444 /* CDVStatusBar.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		301BF551109A68C00062928A /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = CordovaLib;
+			targetProxy = 301BF550109A68C00062928A /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+		1D6058940D05DD3E006BFB54 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 3047A50F1AB8059700498E2A /* build-debug.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CODE_SIGN_IDENTITY = "Apple Development";
+				CODE_SIGN_STYLE = Automatic;
+				COPY_PHASE_STRIP = NO;
+				DEVELOPMENT_TEAM = D5DGD222ZA;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "美天旺/美天旺-Prefix.pch";
+				GCC_THUMB_SUPPORT = NO;
+				GCC_VERSION = "";
+				INFOPLIST_FILE = "美天旺/美天旺-Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)/$(TARGET_NAME)/Plugins/cordova-plugin-jcore\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)/Plugins/cordova-plugin-wechat\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)/Plugins/jpush-phonegap-plugin\"",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.shotshock.twong;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		1D6058950D05DD3E006BFB54 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 3047A5101AB8059700498E2A /* build-release.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CODE_SIGN_IDENTITY = "Apple Development";
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
+				COPY_PHASE_STRIP = YES;
+				DEVELOPMENT_TEAM = D5DGD222ZA;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "美天旺/美天旺-Prefix.pch";
+				GCC_THUMB_SUPPORT = NO;
+				GCC_VERSION = "";
+				INFOPLIST_FILE = "美天旺/美天旺-Info.plist";
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)/$(TARGET_NAME)/Plugins/cordova-plugin-jcore\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)/Plugins/cordova-plugin-wechat\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)/Plugins/jpush-phonegap-plugin\"",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.shotshock.twong;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+		C01FCF4F08A954540054247B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 3047A5111AB8059700498E2A /* build.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_THUMB_SUPPORT = NO;
+				GCC_VERSION = "";
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = NO;
+				WK_WEB_VIEW_ONLY = 1;
+			};
+			name = Debug;
+		};
+		C01FCF5008A954540054247B /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 3047A5111AB8059700498E2A /* build.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = c99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_THUMB_SUPPORT = NO;
+				GCC_VERSION = "";
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				SDKROOT = iphoneos;
+				SKIP_INSTALL = NO;
+				WK_WEB_VIEW_ONLY = 1;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "美天旺" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1D6058940D05DD3E006BFB54 /* Debug */,
+				1D6058950D05DD3E006BFB54 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C01FCF4E08A954540054247B /* Build configuration list for PBXProject "美天旺" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C01FCF4F08A954540054247B /* Debug */,
+				C01FCF5008A954540054247B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}

+ 7 - 0
cordova/platforms/ios/美天旺.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:美天旺.xcodeproj">
+   </FileRef>
+</Workspace>

+ 8 - 0
cordova/platforms/ios/美天旺.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>

+ 91 - 0
cordova/platforms/ios/美天旺.xcworkspace/xcshareddata/xcschemes/美天旺.xcscheme

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0730"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
+               BuildableName = "美天旺.app"
+               BlueprintName = "美天旺"
+               ReferencedContainer = "container:美天旺.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
+            BuildableName = "美天旺.app"
+            BlueprintName = "美天旺"
+            ReferencedContainer = "container:美天旺.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
+            BuildableName = "美天旺.app"
+            BlueprintName = "美天旺"
+            ReferencedContainer = "container:美天旺.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
+            BuildableName = "美天旺.app"
+            BlueprintName = "美天旺"
+            ReferencedContainer = "container:美天旺.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

BIN
cordova/platforms/ios/美天旺.xcworkspace/xcuserdata/x.xcuserdatad/UserInterfaceState.xcuserstate


+ 14 - 0
cordova/platforms/ios/美天旺.xcworkspace/xcuserdata/x.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>美天旺.xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>0</integer>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 6 - 0
cordova/plugins/android.json

@@ -26,6 +26,12 @@
       "ANDROID_HOST": " ",
       "ANDROID_PATHPREFIX": "/",
       "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-fullscreen": {
+      "PACKAGE_NAME": "com.shotshock.twong"
+    },
+    "cordova-plugin-statusbar": {
+      "PACKAGE_NAME": "com.shotshock.twong"
     }
   },
   "dependent_plugins": {

+ 27 - 0
cordova/plugins/cordova-plugin-fullscreen/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2014, Mesmotronic Limited
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+
+* Neither the name of the {organization} nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 104 - 0
cordova/plugins/cordova-plugin-fullscreen/README.md

@@ -0,0 +1,104 @@
+Full Screen Plugin for Cordova
+==============================
+
+Plugin for Cordova (or PhoneGap) 3.0+ to enable true full screen on Android devices using lean and immersive modes, ported from our popular [ANE for Adobe AIR](https://github.com/mesmotronic/air-ane-fullscreen).
+
+Released under BSD license; see LICENSE for details.
+
+How does it work?
+-----------------
+
+This plugin enables developers to offer users a true full screen experience in their Cordova and PhoneGap apps for Android.
+
+Using Android 4.0+, you can use true full screen in "lean mode", the way you see in apps like YouTube, expanding the app right to the edges of the screen, hiding the status and navigation bars until the user next interacts. This is ideally suited to video or cut-scene content.
+
+In Android 4.4+, however, you can now enter true full screen, fully interactive immersive mode. In this mode, your app will remain in true full screen until you choose otherwise; users can swipe down from the top of the screen to temporarily display the system UI.
+
+If you find that the plugin doesn't work as you might like on a specific device or Android configuration you're using, don't forget that this project is open source, so feel free to fork the project and adapt it to work in any way you like!
+
+Installation
+------------
+
+**Cordova**
+
+`cordova plugin add cordova-plugin-fullscreen`
+
+**PhoneGap**
+
+`phonegap local plugin add cordova-plugin-fullscreen`
+
+Notes
+-----
+
+From version 1.0.2, the plugin ID has changed to `cordova-plugin-fullscreen` in line with the official Cordova plugin naming coventions following the switch to NPM. We therefore recommend that any previous version be uninstalled before upgrading to this release.
+
+Since the release of `android@5.0.0`, setting `<preference name="Fullscreen" value="true" />` in `config.xml` will use immersive mode, where available, even without this plugin.
+
+Code example
+------------
+
+Using the plugin in your app couldn't be easier:
+
+```js
+function successFunction()
+{
+    console.info("It worked!");
+}
+
+function errorFunction(error)
+{
+    console.error(error);
+}
+
+function trace(value)
+{
+    console.log(value);
+}
+
+// Is this plugin supported?
+AndroidFullScreen.isSupported(successFunction, errorFunction);
+
+// Is immersive mode supported?
+AndroidFullScreen.isImmersiveModeSupported(successFunction, errorFunction);
+
+// The width of the screen in immersive mode
+AndroidFullScreen.immersiveWidth(trace, errorFunction);
+
+// The height of the screen in immersive mode
+AndroidFullScreen.immersiveHeight(trace, errorFunction);
+
+// Hide system UI until user interacts
+AndroidFullScreen.leanMode(successFunction, errorFunction);
+
+// Show system UI
+AndroidFullScreen.showSystemUI(successFunction, errorFunction);
+
+// Extend your app underneath the status bar (Android 4.4+ only)
+AndroidFullScreen.showUnderStatusBar(successFunction, errorFunction);
+
+// Extend your app underneath the system UI (Android 4.4+ only)
+AndroidFullScreen.showUnderSystemUI(successFunction, errorFunction);
+
+// Hide system UI and keep it hidden (Android 4.4+ only)
+AndroidFullScreen.immersiveMode(successFunction, errorFunction);
+
+// Custom full screen mode
+// See https://developer.android.com/reference/android/view/View.html#setSystemUiVisibility(int)
+AndroidFullScreen.setSystemUiVisibility(AndroidFullScreen.SYSTEM_UI_FLAG_FULLSCREEN | AndroidFullScreen.SYSTEM_UI_FLAG_LOW_PROFILE, successFunction, errorFunction);
+```
+
+All methods will call the successFunction callback if the action was successful and the errorFunction if it wasn't (or isn't supported); if you're using the plugin in an app for a platform other than Android, all methods will fail.
+
+The `immersiveWidth` and `immersiveHeight` properties return the screen width and height available in immersive mode (or with the system UI hidden), where supported.
+
+Getting the immersive screen size
+---------------------------------
+
+You can use the `immersiveWidth` and `immersiveHeight` methods to find out the dimensions of the screen with the system UI hidden, regardless of the current screen state.
+
+Make a donation
+---------------
+
+If you find this project useful, why not buy us a coffee (or as many as you think it's worth)?
+
+[![Make a donation](https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif)](http://bit.ly/2W0K8iE)

+ 7 - 0
cordova/plugins/cordova-plugin-fullscreen/example/README.md

@@ -0,0 +1,7 @@
+You need to add the Android platform and install the plugin before running the example:
+
+```
+cordova platform add android
+cordova plugin add https://github.com/mesmotronic/cordova-plugin-fullscreen.git
+cordova run android
+```

+ 13 - 0
cordova/plugins/cordova-plugin-fullscreen/example/config.xml

@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="com.mesmotronic.fullscreen.test" version="0.0.2" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>Cordova Full Screen Test</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+    <!-- <preference name="Fullscreen" value="false" /> -->
+</widget>

+ 83 - 0
cordova/plugins/cordova-plugin-fullscreen/example/hooks/README.md

@@ -0,0 +1,83 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+-->
+# Cordova Hooks
+
+This directory may contain scripts used to customize cordova commands. This
+directory used to exist at `.cordova/hooks`, but has now been moved to the
+project root. Any scripts you add to these directories will be executed before
+and after the commands corresponding to the directory name. Useful for
+integrating your own build systems or integrating with version control systems.
+
+__Remember__: Make your scripts executable.
+
+## Hook Directories
+The following subdirectories will be used for hooks:
+
+    after_build/
+    after_compile/
+    after_docs/
+    after_emulate/
+    after_platform_add/
+    after_platform_rm/
+    after_platform_ls/
+    after_plugin_add/
+    after_plugin_ls/
+    after_plugin_rm/
+    after_plugin_search/
+    after_prepare/
+    after_run/
+    after_serve/
+    before_build/
+    before_compile/
+    before_docs/
+    before_emulate/
+    before_platform_add/
+    before_platform_rm/
+    before_platform_ls/
+    before_plugin_add/
+    before_plugin_ls/
+    before_plugin_rm/
+    before_plugin_search/
+    before_prepare/
+    before_run/
+    before_serve/
+    pre_package/ <-- Windows 8 and Windows Phone only.
+
+## Script Interface
+
+All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:
+
+* CORDOVA_VERSION - The version of the Cordova-CLI.
+* CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios).
+* CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer)
+* CORDOVA_HOOK - Path to the hook that is being executed.
+* CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate)
+
+If a script returns a non-zero exit code, then the parent cordova command will be aborted.
+
+
+## Writing hooks
+
+We highly recommend writting your hooks using Node.js so that they are
+cross-platform. Some good examples are shown here:
+
+[http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/)
+

+ 64 - 0
cordova/plugins/cordova-plugin-fullscreen/package.json

@@ -0,0 +1,64 @@
+{
+  "_from": "cordova-plugin-fullscreen",
+  "_id": "cordova-plugin-fullscreen@1.3.0",
+  "_inBundle": false,
+  "_integrity": "sha1-JXOduEHSIQbdzSan3igpOFx/M4I=",
+  "_location": "/cordova-plugin-fullscreen",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "cordova-plugin-fullscreen",
+    "name": "cordova-plugin-fullscreen",
+    "escapedName": "cordova-plugin-fullscreen",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#DEV:/",
+    "#USER"
+  ],
+  "_resolved": "https://registry.npm.taobao.org/cordova-plugin-fullscreen/download/cordova-plugin-fullscreen-1.3.0.tgz",
+  "_shasum": "25739db841d22106ddcd26a7de2829385c7f3382",
+  "_spec": "cordova-plugin-fullscreen",
+  "_where": "/Users/x/Documents/twong-h5/cordova",
+  "author": {
+    "name": "Neil Rackett"
+  },
+  "bugs": {
+    "url": "https://github.com/mesmotronic/cordova-fullscreen-plugin/issues"
+  },
+  "bundleDependencies": false,
+  "cordova": {
+    "id": "cordova-plugin-fullscreen",
+    "platforms": [
+      "android"
+    ]
+  },
+  "deprecated": false,
+  "description": "Plugin for Cordova (or PhoneGap) 3.0+ to enable true full screen on Android devices using lean and immersive modes",
+  "engines": [
+    {
+      "name": "cordova",
+      "version": ">=3.0.0"
+    }
+  ],
+  "homepage": "https://github.com/mesmotronic/cordova-fullscreen-plugin#readme",
+  "keywords": [
+    "cordova",
+    "android",
+    "fullscreen",
+    "lean",
+    "immersive",
+    "ecosystem:cordova",
+    "cordova-android"
+  ],
+  "license": "BSD",
+  "name": "cordova-plugin-fullscreen",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/mesmotronic/cordova-fullscreen-plugin.git"
+  },
+  "version": "1.3.0"
+}

+ 78 - 0
cordova/plugins/cordova-plugin-fullscreen/plugin.xml

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Copyright (c) 2020, Mesmotronic Limited
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+
+* Neither the name of the organization nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<plugin
+  xmlns="http://apache.org/cordova/ns/plugins/1.0"
+  xmlns:android="http://schemas.android.com/apk/res/android"
+  id="cordova-plugin-fullscreen"
+  version="1.3.0"
+  >
+
+  <name>cordova-plugin-fullscreen</name>
+  <description>Plugin for Cordova (or PhoneGap) 3.0+ to enable true full screen on Android devices using lean and immersive modes</description>
+  <keywords>cordova,android,fullscreen,lean,immersive,statusbar</keywords>
+  <repo>https://github.com/mesmotronic/cordova-fullscreen-plugin.git</repo>
+
+  <license>BSD</license>
+
+  <engines>
+    <engine name="cordova" version=">=3.0.0" />
+  </engines>
+
+  <js-module 
+    src="www/AndroidFullScreen.js" 
+    name="AndroidFullScreen"
+    >
+      <clobbers target="AndroidFullScreen" />
+  </js-module>
+
+  <!-- android -->
+  <platform name="android">
+    <config-file target="res/xml/config.xml" parent="/*">
+      <feature name="AndroidFullScreen">
+        <param 
+          name="android-package" 
+          value="com.mesmotronic.plugins.FullScreenPlugin" 
+          />
+      </feature>
+    </config-file>
+    <!-- Adds support for screen ratios wider than 16:9 -->
+    <config-file target="AndroidManifest.xml" parent="/manifest/application">
+      <meta-data android:name="android.max_aspect" android:value="2.16" />
+    </config-file>    
+    <source-file
+      src="src/android/com/mesmotronic/plugins/FullScreenPlugin.java" 
+      target-dir="src/com/mesmotronic/plugins" 
+      />
+   </platform>
+   
+</plugin>

+ 532 - 0
cordova/plugins/cordova-plugin-fullscreen/src/android/com/mesmotronic/plugins/FullScreenPlugin.java

@@ -0,0 +1,532 @@
+package com.mesmotronic.plugins;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.PluginResult;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaWebView;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.app.Activity;
+import android.graphics.Point;
+import android.os.Build;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.graphics.Color;
+import android.os.Handler;
+
+public class FullScreenPlugin extends CordovaPlugin
+{
+	public static final String ACTION_IS_SUPPORTED = "isSupported";
+	public static final String ACTION_IS_IMMERSIVE_MODE_SUPPORTED = "isImmersiveModeSupported";
+	public static final String ACTION_IMMERSIVE_WIDTH = "immersiveWidth";
+	public static final String ACTION_IMMERSIVE_HEIGHT = "immersiveHeight";
+	public static final String ACTION_LEAN_MODE = "leanMode";
+	public static final String ACTION_SHOW_SYSTEM_UI = "showSystemUI";
+	public static final String ACTION_SHOW_UNDER_STATUS_BAR = "showUnderStatusBar";
+	public static final String ACTION_SHOW_UNDER_SYSTEM_UI = "showUnderSystemUI";
+	public static final String ACTION_IMMERSIVE_MODE = "immersiveMode";
+	public static final String ACTION_SET_SYSTEM_UI_VISIBILITY = "setSystemUiVisibility";
+	public static final String ACTION_RESET_WINDOW = "resetScreen";
+	
+	private CallbackContext context;
+	private Activity activity;
+	private Window window;
+	private View decorView;
+	private int mLastSystemUIVisibility = 0;
+	private final Handler mLeanBackHandler = new Handler();
+	private final Runnable mEnterLeanback = new Runnable() {
+	    @Override
+	    public void run() {
+	        leanMode();
+	    }
+	};
+	
+	/**
+     * Sets the context of the Command. This can then be used to do things like
+     * get file paths associated with the Activity.
+     *
+     * @param cordova The context of the main Activity.
+     * @param webView The CordovaWebView Cordova is running in.
+     */
+    @Override
+    public void initialize(final CordovaInterface cordova, final CordovaWebView webView) {
+        super.initialize(cordova, webView);
+
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Clear flag FLAG_FORCE_NOT_FULLSCREEN which is set initially
+                // by the Cordova.
+                Window window = cordova.getActivity().getWindow();
+                window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+
+                // Read 'StatusBarBackgroundColor' from config.xml, default is #000000.
+                setStatusBarBackgroundColor(preferences.getString("StatusBarBackgroundColor", "#000000"));
+            }
+        });
+    }
+
+	@Override
+	public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException
+	{
+		context = callbackContext;
+		activity = cordova.getActivity();
+		window = activity.getWindow();
+		decorView = window.getDecorView();
+		
+		if (ACTION_IS_SUPPORTED.equals(action))
+			return isSupported();
+		else if (ACTION_IS_IMMERSIVE_MODE_SUPPORTED.equals(action))
+			return isImmersiveModeSupported();
+		else if (ACTION_IMMERSIVE_WIDTH.equals(action))
+			return immersiveWidth();
+		else if (ACTION_IMMERSIVE_HEIGHT.equals(action))
+			return immersiveHeight();
+		else if (ACTION_LEAN_MODE.equals(action))
+			return leanMode();
+		else if (ACTION_SHOW_SYSTEM_UI.equals(action))
+			return showSystemUI();
+		else if (ACTION_SHOW_UNDER_STATUS_BAR.equals(action))
+			return showUnderStatusBar();
+		else if (ACTION_SHOW_UNDER_SYSTEM_UI.equals(action))
+			return showUnderSystemUI();
+		else if (ACTION_IMMERSIVE_MODE.equals(action))
+			return immersiveMode();
+		else if (ACTION_SET_SYSTEM_UI_VISIBILITY.equals(action))
+			return setSystemUiVisibility(args.getInt(0));
+		else if (ACTION_RESET_WINDOW.equals(action))
+			return resetScreen();
+		
+		return false;
+	}
+	
+	protected void resetWindow()
+	{
+		decorView.setOnFocusChangeListener(null); 
+		decorView.setOnSystemUiVisibilityChangeListener(null);
+		
+		window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+	}
+	
+	/**
+	 * Are any of the features of this plugin supported?
+	 */
+	protected boolean isSupported()
+	{
+		boolean supported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+		
+        PluginResult res = new PluginResult(PluginResult.Status.OK, supported);
+        context.sendPluginResult(res);
+		return supported;
+	}
+	
+	/**
+	 * Is immersive mode supported?
+	 */
+	protected boolean isImmersiveModeSupported()
+	{
+		boolean supported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+		
+        PluginResult res = new PluginResult(PluginResult.Status.OK, supported);
+        context.sendPluginResult(res);
+		return supported;
+	}
+	
+	/**
+	 * The width of the screen in immersive mode
+	 */
+	protected boolean immersiveWidth()
+	{
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					Point outSize = new Point();
+					
+					decorView.getDisplay().getRealSize(outSize);
+					
+			        PluginResult res = new PluginResult(PluginResult.Status.OK, outSize.x);
+			        context.sendPluginResult(res);
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+		
+		return true;
+	}
+	
+	/**
+	 * The height of the screen in immersive mode
+	 */	
+	protected boolean immersiveHeight()
+	{
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					Point outSize = new Point();
+					
+					decorView.getDisplay().getRealSize(outSize);
+					
+			        PluginResult res = new PluginResult(PluginResult.Status.OK, outSize.y);
+			        context.sendPluginResult(res);
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+        
+		return true;
+	}
+	
+	/**
+	 * Hide system UI until user interacts
+	 */
+	protected boolean leanMode()
+	{
+		if (!isSupported())
+		{
+			context.error("Not supported");
+			return false;
+		}
+		
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					resetWindow();
+					
+					int uiOptions = 
+						View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+						| View.SYSTEM_UI_FLAG_FULLSCREEN
+			            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+			            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+			            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+					
+					mLastSystemUIVisibility = uiOptions;
+					decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
+					{
+						@Override
+						public void onSystemUiVisibilityChange(int visibility) 
+						{
+							if((mLastSystemUIVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+                 					&& (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+        						resetHideTimer();
+    						}
+    						mLastSystemUIVisibility = visibility;
+						}
+					});
+
+					decorView.setSystemUiVisibility(uiOptions);
+					
+					context.success();
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+		
+		return true;
+	}
+
+	private void resetHideTimer() {
+	    // First cancel any queued events - i.e. resetting the countdown clock
+	    mLeanBackHandler.removeCallbacks(mEnterLeanback);
+	    // And fire the event in 3s time
+	    mLeanBackHandler.postDelayed(mEnterLeanback, 3000);
+	}
+	
+	/**
+	 * Show system UI
+	 */
+	protected boolean showSystemUI()
+	{
+		if (!isSupported())
+		{
+			context.error("Not supported");
+			return false;
+		}
+		
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					resetWindow();
+			        
+					// Remove translucent theme from bars
+					
+					window.clearFlags
+					(
+						WindowManager.LayoutParams.FLAG_FULLSCREEN 
+						| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION 
+						| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+					);
+					
+			        // Update system UI
+					
+					decorView.setOnSystemUiVisibilityChangeListener(null);
+					decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+					
+					PluginResult res = new PluginResult(PluginResult.Status.OK, true);
+			        context.sendPluginResult(res);
+					
+					context.success();
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});			
+		
+		return true;
+	}
+	
+	/**
+	 * Extend your app underneath the status bar (Android 4.4+ only)
+	 */
+	protected boolean showUnderStatusBar()
+	{
+		if (!isImmersiveModeSupported())
+		{
+			context.error("Not supported");
+			return false;
+		}
+		
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					resetWindow();
+					
+					// Make the status bar translucent
+					
+			        window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+			        
+			        // Extend view underneath status bar
+					
+					int uiOptions = 
+						View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+						| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+						| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+
+					decorView.setSystemUiVisibility(uiOptions);
+					
+					context.success();
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+		
+		return true;
+	}
+
+	/**
+	 * Undo the effect of any of the other methods of this plugin
+	 */
+	protected boolean resetScreen()
+	{
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+					context.success();
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+		
+		return true;
+	}
+	
+	/**
+	 * Extend your app underneath the system UI (Android 4.4+ only)
+	 */
+	protected boolean showUnderSystemUI()
+	{
+		if (!isImmersiveModeSupported())
+		{
+			context.error("Not supported");
+			return false;
+		}
+		
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					resetWindow();
+					
+					// Make the status and nav bars translucent
+					
+					window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+					window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+					
+					// Extend view underneath status and nav bars
+					
+					int uiOptions = 
+							View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+							| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+					
+					decorView.setSystemUiVisibility(uiOptions);
+					
+					context.success();
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+		
+		return true;
+	}
+	
+	/**
+	 * Hide system UI and switch to immersive mode (Android 4.4+ only)
+	 */
+	protected boolean immersiveMode()
+	{
+		if (!isImmersiveModeSupported())
+		{
+			context.error("Not supported");
+			return false;
+		}
+		
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					resetWindow();
+					
+					final int uiOptions = 
+						View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+						| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+						| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+						| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+						| View.SYSTEM_UI_FLAG_FULLSCREEN
+						| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+					
+					window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+					decorView.setSystemUiVisibility(uiOptions);
+					
+					decorView.setOnFocusChangeListener(new View.OnFocusChangeListener() 
+					{
+						@Override
+						public void onFocusChange(View v, boolean hasFocus) 
+						{
+							if (hasFocus)
+							{
+								decorView.setSystemUiVisibility(uiOptions);
+							}
+						}
+					});
+					
+					decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
+					{
+						@Override
+						public void onSystemUiVisibilityChange(int visibility) 
+						{
+							decorView.setSystemUiVisibility(uiOptions);
+						}
+					});
+					
+					context.success();
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+			
+		return true;
+	}
+	
+	protected boolean setSystemUiVisibility(final int visibility)
+	{
+		if (!isSupported())
+		{
+			context.error("Not supported");
+			return false;
+		}
+		
+		activity.runOnUiThread(new Runnable()
+		{
+			@Override
+			public void run() 
+			{
+				try
+				{
+					resetWindow();
+					decorView.setSystemUiVisibility(visibility);
+					context.success();
+				}
+				catch (Exception e)
+				{
+					context.error(e.getMessage());
+				}
+			}
+		});
+		
+		return true;
+	}
+	
+	private void setStatusBarBackgroundColor(final String colorPref) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            if (colorPref != null && !colorPref.isEmpty()) {
+                final Window window = cordova.getActivity().getWindow();
+                // Method and constants not available on all SDKs but we want to be able to compile this code with any SDK
+                window.clearFlags(0x04000000); // SDK 19: WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                window.addFlags(0x80000000); // SDK 21: WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+                try {
+                    // Using reflection makes sure any 5.0+ device will work without having to compile with SDK level 21
+                    window.getClass().getDeclaredMethod("setStatusBarColor", int.class).invoke(window, Color.parseColor(colorPref));
+                } catch (IllegalArgumentException ignore) {
+                } catch (Exception ignore) {
+                }
+            }
+        }
+    }
+	
+}

+ 16 - 0
cordova/plugins/cordova-plugin-statusbar/.jshintrc

@@ -0,0 +1,16 @@
+{
+    "browser": true
+  , "devel": true
+  , "bitwise": true
+  , "undef": true
+  , "trailing": true
+  , "quotmark": false
+  , "indent": 4
+  , "unused": "vars"
+  , "latedef": "nofunc"
+  , "globals": {
+        "module": false,
+        "exports": false,
+        "require": false
+    }
+}

+ 37 - 0
cordova/plugins/cordova-plugin-statusbar/CONTRIBUTING.md

@@ -0,0 +1,37 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+-->
+
+# Contributing to Apache Cordova
+
+Anyone can contribute to Cordova. And we need your contributions.
+
+There are multiple ways to contribute: report bugs, improve the docs, and
+contribute code.
+
+For instructions on this, start with the 
+[contribution overview](http://cordova.apache.org/contribute/).
+
+The details are explained there, but the important items are:
+ - Sign and submit an Apache ICLA (Contributor License Agreement).
+ - Have a Jira issue open that corresponds to your contribution.
+ - Run the tests so your patch doesn't break existing functionality.
+
+We look forward to your contributions!

+ 202 - 0
cordova/plugins/cordova-plugin-statusbar/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 5 - 0
cordova/plugins/cordova-plugin-statusbar/NOTICE

@@ -0,0 +1,5 @@
+Apache Cordova
+Copyright 2012 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).

+ 341 - 0
cordova/plugins/cordova-plugin-statusbar/README.md

@@ -0,0 +1,341 @@
+---
+title: Statusbar
+description: Control the device status bar.
+---
+<!---
+# license: Licensed to the Apache Software Foundation (ASF) under one
+#         or more contributor license agreements.  See the NOTICE file
+#         distributed with this work for additional information
+#         regarding copyright ownership.  The ASF licenses this file
+#         to you under the Apache License, Version 2.0 (the
+#         "License"); you may not use this file except in compliance
+#         with the License.  You may obtain a copy of the License at
+#
+#           http://www.apache.org/licenses/LICENSE-2.0
+#
+#         Unless required by applicable law or agreed to in writing,
+#         software distributed under the License is distributed on an
+#         "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#         KIND, either express or implied.  See the License for the
+#         specific language governing permissions and limitations
+#         under the License.
+-->
+
+|AppVeyor|Travis CI|
+|:-:|:-:|
+|[![Build status](https://ci.appveyor.com/api/projects/status/github/apache/cordova-plugin-statusbar?branch=master)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-plugin-statusbar)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-statusbar.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-statusbar)|
+
+# cordova-plugin-statusbar
+
+> The `StatusBar` object provides some functions to customize the iOS and Android StatusBar.
+
+## Installation
+
+This installation method requires cordova 5.0+
+
+    cordova plugin add cordova-plugin-statusbar
+Older versions of cordova can still install via the __deprecated__ id
+
+    cordova plugin add org.apache.cordova.statusbar
+It is also possible to install via repo url directly ( unstable )
+
+    cordova plugin add https://github.com/apache/cordova-plugin-statusbar.git
+
+
+Preferences
+-----------
+
+#### config.xml
+
+-  __StatusBarOverlaysWebView__ (boolean, defaults to true). Make the statusbar overlay or not overlay the WebView at startup.
+
+        <preference name="StatusBarOverlaysWebView" value="true" />
+
+    ##### Android Quirks
+    
+    Only supported on Android 5 or later. Earlier versions will ignore this preference.
+
+- __StatusBarBackgroundColor__ (color hex string, no default value). Set the background color of the statusbar by a hex string (#RRGGBB) at startup. If this value is not set, the background color will be transparent.
+
+        <preference name="StatusBarBackgroundColor" value="#000000" />
+
+- __StatusBarStyle__ (status bar style, defaults to lightcontent). Set the status bar style. Available options default, lightcontent, blacktranslucent, blackopaque.
+
+        <preference name="StatusBarStyle" value="lightcontent" />
+
+- __StatusBarDefaultScrollToTop__ (boolean, defaults to false). On iOS, allows the Cordova WebView to use default scroll-to-top behavior. Defaults to false so you can listen to the "statusTap" event (described below) and customize the behavior instead.
+
+        <preference name="StatusBarDefaultScrollToTop" value="false" />
+
+### Android Quirks
+The Android 5+ guidelines specify using a different color for the statusbar than your main app color (unlike the uniform statusbar color of many iOS apps), so you may want to set the statusbar color at runtime instead via `StatusBar.backgroundColorByHexString` or `StatusBar.backgroundColorByName`. One way to do that would be:
+```js
+if (cordova.platformId == 'android') {
+    StatusBar.backgroundColorByHexString("#333");
+}
+```
+
+It is also possible to make the status bar semi-transparent. Android uses hexadecimal ARGB values, which are formatted as #AARRGGBB. That first pair of letters, the AA, represent the alpha channel. You must convert your decimal opacity values to a hexadecimal value. You can read more about it [here](https://stackoverflow.com/questions/5445085/understanding-colors-on-android-six-characters/11019879#11019879).
+
+For example, a black status bar with 20% opacity:
+```js
+if (cordova.platformId == 'android') {
+    StatusBar.overlaysWebView(true);
+    StatusBar.backgroundColorByHexString('#33000000');
+}
+```
+
+Hiding at startup
+-----------
+
+During runtime you can use the StatusBar.hide function below, but if you want the StatusBar to be hidden at app startup on iOS, you must modify your app's Info.plist file.
+
+Add/edit these two attributes if not present. Set **"Status bar is initially hidden"** to **"YES"** and set **"View controller-based status bar appearance"** to **"NO"**. If you edit it manually without Xcode, the keys and values are:
+
+
+	<key>UIStatusBarHidden</key>
+	<true/>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<false/>
+
+
+Methods
+-------
+This plugin defines global `StatusBar` object.
+
+Although in the global scope, it is not available until after the `deviceready` event.
+
+    document.addEventListener("deviceready", onDeviceReady, false);
+    function onDeviceReady() {
+        console.log(StatusBar);
+    }
+
+- StatusBar.overlaysWebView
+- StatusBar.styleDefault
+- StatusBar.styleLightContent
+- StatusBar.styleBlackTranslucent
+- StatusBar.styleBlackOpaque
+- StatusBar.backgroundColorByName
+- StatusBar.backgroundColorByHexString
+- StatusBar.hide
+- StatusBar.show
+
+Properties
+--------
+
+- StatusBar.isVisible
+
+Events
+------
+
+- statusTap
+
+StatusBar.overlaysWebView
+=================
+
+Make the statusbar overlay or not overlay the WebView.
+
+    StatusBar.overlaysWebView(true);
+
+Description
+-----------
+
+Set to true to make the statusbar overlay on top of your app. Ensure that you adjust your styling accordingly so that your app's title bar or content is not covered. Set to false to make the statusbar solid and not overlay your app. You can then set the style and background color to suit using the other functions.
+
+
+Supported Platforms
+-------------------
+
+- iOS 7+
+- Android 5+
+
+Quick Example
+-------------
+
+    StatusBar.overlaysWebView(true);
+    StatusBar.overlaysWebView(false);
+
+StatusBar.styleDefault
+=================
+
+Use the default statusbar (dark text, for light backgrounds).
+
+    StatusBar.styleDefault();
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android 6+
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+StatusBar.styleLightContent
+=================
+
+Use the lightContent statusbar (light text, for dark backgrounds).
+
+    StatusBar.styleLightContent();
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android 6+
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+StatusBar.styleBlackTranslucent
+=================
+
+Use the blackTranslucent statusbar (light text, for dark backgrounds).
+
+    StatusBar.styleBlackTranslucent();
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android 6+
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+StatusBar.styleBlackOpaque
+=================
+
+Use the blackOpaque statusbar (light text, for dark backgrounds).
+
+    StatusBar.styleBlackOpaque();
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android 6+
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+
+StatusBar.backgroundColorByName
+=================
+
+On iOS, when you set StatusBar.overlaysWebView to false, you can set the background color of the statusbar by color name.
+
+    StatusBar.backgroundColorByName("red");
+
+Supported color names are:
+
+    black, darkGray, lightGray, white, gray, red, green, blue, cyan, yellow, magenta, orange, purple, brown
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android 5+
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+StatusBar.backgroundColorByHexString
+=================
+
+Sets the background color of the statusbar by a hex string.
+
+    StatusBar.backgroundColorByHexString("#C0C0C0");
+
+CSS shorthand properties are also supported.
+
+    StatusBar.backgroundColorByHexString("#333"); // => #333333
+    StatusBar.backgroundColorByHexString("#FAB"); // => #FFAABB
+
+On iOS, when you set StatusBar.overlaysWebView to false, you can set the background color of the statusbar by a hex string (#RRGGBB).
+
+On Android, when StatusBar.overlaysWebView is true, and on WP7&8, you can also specify values as #AARRGGBB, where AA is an alpha value.
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android 5+
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+StatusBar.hide
+=================
+
+Hide the statusbar.
+
+    StatusBar.hide();
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+StatusBar.show
+=================
+
+Shows the statusbar.
+
+    StatusBar.show();
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+
+StatusBar.isVisible
+=================
+
+Read this property to see if the statusbar is visible or not.
+
+    if (StatusBar.isVisible) {
+    	// do something
+    }
+
+
+Supported Platforms
+-------------------
+
+- iOS
+- Android
+- Windows Phone 7
+- Windows Phone 8
+- Windows Phone 8.1
+
+
+statusTap
+=========
+
+Listen for this event to know if the statusbar was tapped.
+
+    window.addEventListener('statusTap', function() {
+        // scroll-up with document.body.scrollTop = 0; or do whatever you want
+    });
+
+
+Supported Platforms
+-------------------
+
+- iOS

+ 191 - 0
cordova/plugins/cordova-plugin-statusbar/RELEASENOTES.md

@@ -0,0 +1,191 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+-->
+# Release Notes
+
+### 2.4.3 (Jun 19, 2019)
+
+-   docs: Improved documentation and removed text that implies iOS only ([#130](https://github.com/apache/cordova-plugin-statusbar/issues/130)) ([`33e410a`](https://github.com/apache/cordova-plugin-statusbar/commit/33e410a), [`14b1513`](https://github.com/apache/cordova-plugin-statusbar/commit/14b1513))
+-   docs: Alpha example doesn't match description ([#100](https://github.com/apache/cordova-plugin-statusbar/issues/100)) ([`5b77cae`](https://github.com/apache/cordova-plugin-statusbar/commit/5b77cae), [`9b5baa2`](https://github.com/apache/cordova-plugin-statusbar/commit/9b5baa2))
+-   chore(types): remove version from types ([`fade76b`](https://github.com/apache/cordova-plugin-statusbar/commit/fade76b))
+-   chore: fix github issues link ([`288bd71`](https://github.com/apache/cordova-plugin-statusbar/commit/288bd71))
+-   docs: remove outdated translations ([`8dacefa`](https://github.com/apache/cordova-plugin-statusbar/commit/8dacefa))
+-   build: add `.npmignore` to remove unneeded files from npm package ([`84081de`](https://github.com/apache/cordova-plugin-statusbar/commit/84081de))
+-   build: add `.gitattributes` to force LF (instead of possible CRLF on Windows) ([`da6c2a8`](https://github.com/apache/cordova-plugin-statusbar/commit/da6c2a8))
+-   ci(travis): Update Travis CI configuration for new paramedic ([#139](https://github.com/apache/cordova-plugin-statusbar/issues/139)) ([`a538bfe`](https://github.com/apache/cordova-plugin-statusbar/commit/a538bfe))
+-   feat: update typings ([#132](https://github.com/apache/cordova-plugin-statusbar/issues/132)) ([`003fa61`](https://github.com/apache/cordova-plugin-statusbar/commit/003fa61))
+-   chore: drop Node.js v4 support ([#124](https://github.com/apache/cordova-plugin-statusbar/issues/124)) ([`a07612a`](https://github.com/apache/cordova-plugin-statusbar/commit/a07612a))
+-   chore(github): Add or update GitHub pull request and issue template ([`727eea3`](https://github.com/apache/cordova-plugin-statusbar/commit/727eea3))
+-   docs: remove JIRA link ([`adcee9f`](https://github.com/apache/cordova-plugin-statusbar/commit/adcee9f))
+-   ci(travis): also accept terms for android sdk `android-27` ([`c8a13b8`](https://github.com/apache/cordova-plugin-statusbar/commit/c8a13b8))
+-   docs: remove second title headline ([`ecf8ccd`](https://github.com/apache/cordova-plugin-statusbar/commit/ecf8ccd))
+-   docs: Add Android overlay support to README ([#97](https://github.com/apache/cordova-plugin-statusbar/issues/97)) ([`e0256b2`](https://github.com/apache/cordova-plugin-statusbar/commit/e0256b2), [`053a902`](https://github.com/apache/cordova-plugin-statusbar/commit/053a902))
+
+
+### 2.4.2 (Apr 12, 2018)
+* [CB-12679](https://issues.apache.org/jira/browse/CB-12679) Remove Permissions section
+
+### 2.4.1 (Dec 27, 2017)
+* [CB-13712](https://issues.apache.org/jira/browse/CB-13712) (iOS): fix overlaysWebView reset on rotation (#92)
+
+### 2.4.0 (Dec 15, 2017)
+* [CB-13623](https://issues.apache.org/jira/browse/CB-13623) (iOS): Remove **iOS** 6-7 code
+
+### 2.3.0 (Nov 06, 2017)
+* [CB-13476](https://issues.apache.org/jira/browse/CB-13476) (iOS): handle double size statusbar on SDK 10 for **iOS 11**
+* [CB-13394](https://issues.apache.org/jira/browse/CB-13394) (iOS): fix `iPhone X` StatusBar rendering in landscape
+* [CB-11858](https://issues.apache.org/jira/browse/CB-11858) (android) Add `StatusBarStyle` feature support for **Android M+**
+* [CB-13311](https://issues.apache.org/jira/browse/CB-13311) (iOS) Statusbar does not overlay correctly on `iPhone X`
+* [CB-13028](https://issues.apache.org/jira/browse/CB-13028) (CI) **Browser** builds on Travis and AppVeyor
+* [CB-12812](https://issues.apache.org/jira/browse/CB-12812) (browser) Fix statusbar plugin with **Browser** platform
+* [CB-12847](https://issues.apache.org/jira/browse/CB-12847) added `bugs` entry to `package.json`.
+
+### 2.2.3 (Apr 27, 2017)
+* [CB-12622](https://issues.apache.org/jira/browse/CB-12622) Added **Android 6.0** build badge to `README`
+* [CB-10879](https://issues.apache.org/jira/browse/CB-10879) Enable overlaysWebView on **Android** API 21+
+* [CB-12685](https://issues.apache.org/jira/browse/CB-12685) added `package.json` to tests folder
+
+### 2.2.2 (Feb 28, 2017)
+* [CB-12188](https://issues.apache.org/jira/browse/CB-12188) Status Bar is not changing in some specific **Android** phone (Red MI 3s Prime)
+* [CB-12369](https://issues.apache.org/jira/browse/CB-12369) Add plugin typings from `DefinitelyTyped` 
+* [CB-12363](https://issues.apache.org/jira/browse/CB-12363) Added build badges for **iOS 9.3** and **iOS 10.0** 
+* [CB-12196](https://issues.apache.org/jira/browse/CB-12196) **iOS** fix Status Bar Not Hiding
+* [CB-12141](https://issues.apache.org/jira/browse/CB-12141) **iOS** fix white app screen after camera overlay shown on iPad
+* [CB-12230](https://issues.apache.org/jira/browse/CB-12230) Removed **Windows 8.1** build badges
+
+### 2.2.1 (Dec 07, 2016)
+* [CB-12224](https://issues.apache.org/jira/browse/CB-12224) Updated version and RELEASENOTES.md for release 2.2.1
+* [CB-10288](https://issues.apache.org/jira/browse/CB-10288) statusbar plugin interaction with iOS multitasking
+* [CB-10158](https://issues.apache.org/jira/browse/CB-10158) (ios) fix StatusBar issue when recovering from fullscreen video
+* [CB-10341](https://issues.apache.org/jira/browse/CB-10341) ios, document statusTap event
+* [CB-11191](https://issues.apache.org/jira/browse/CB-11191) Statusbar plugin causing issues with webview size
+* [CB-11917](https://issues.apache.org/jira/browse/CB-11917) - Remove pull request template checklist item: "iCLA has been submitted…"
+* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Incremented plugin version.
+
+### 2.2.0 (Sep 08, 2016)
+* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies
+* Handle extended status bar on **iOS**
+* Plugin uses `Android Log class` and not `Cordova LOG class`
+* [CB-11287](https://issues.apache.org/jira/browse/CB-11287) (**ios**) - fix webview resize after modal on **iPhones**
+* [CB-11485](https://issues.apache.org/jira/browse/CB-11485) fix resize on rotation with popover
+* Add badges for paramedic builds on Jenkins
+* [CB-11197](https://issues.apache.org/jira/browse/CB-11197) Keep status bar hidden when keyboard pops up
+* Add pull request template.
+* [CB-10866](https://issues.apache.org/jira/browse/CB-10866) Adding engine info to `package.json`
+* patched missing `_ready` method, and changed the way the proxy is installed
+* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to `README.md`
+
+### 2.1.3 (Apr 15, 2016)
+* [CB-11018](https://issues.apache.org/jira/browse/CB-11018) Fix statusbar with `inappbrowser` causing incorrect orientation on **iOS8**
+* [CB-10884](https://issues.apache.org/jira/browse/CB-10884) `Inappbrowser` breaks UI while Screen orientation changes from landscape to portrait on **iOS**
+
+### 2.1.2 (Mar 09, 2016)
+* [CB-10752](https://issues.apache.org/jira/browse/CB-10752) for for status bar overlays the webview on **iOS** 6 in some cases
+* [CB-10683](https://issues.apache.org/jira/browse/CB-10683) Fix wrong StatusBar.isVisible initial value on **Windows**
+* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add JSHint for plugins
+* [CB-10047](https://issues.apache.org/jira/browse/CB-10047) fix **iOS** 8 deprecated warnings
+
+### 2.1.1 (Feb 09, 2016)
+* [CB-10102](https://issues.apache.org/jira/browse/CB-10102) The removeObserver code was wrong and it might crash on plugin deallocation
+
+### 2.1.0 (Jan 15, 2016)
+* [CB-9513](https://issues.apache.org/jira/browse/CB-9513) Allow to show/hide status bar in fullscreen mode.
+* [CB-8720](https://issues.apache.org/jira/browse/CB-8720) Fix status bar position when app started upside down on **iOS 7**.
+* [CB-10118](https://issues.apache.org/jira/browse/CB-10118) Fixes plugin loading error for **Browser** platform
+
+### 2.0.0 (Nov 18, 2015)
+* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest
+* Added `weakSelf` reference for block use
+* Fixes [CB-4712](https://issues.apache.org/jira/browse/CB-4712), [CB-5439](https://issues.apache.org/jira/browse/CB-5439) statusbar issues
+* Fixing contribute link.
+* [CB-7965](https://issues.apache.org/jira/browse/CB-7965) Add cordova-plugin-statusbar support for **Browser** platform
+* Don't use `IsAtLeastiOSVersion` macro to determine height
+* Use correct statusbar height for landscape orientation in iOS >= 8
+* remove travis-ci
+* [CB-9202](https://issues.apache.org/jira/browse/CB-9202) updated repo url to github mirror in package.json
+* Added verbose install text for users on < cordova 5.0
+* update docs for `StatusBarBackgroundColor`
+
+### 1.0.1 (Jun 17, 2015)
+* add auto-tests for basic api
+* [CB-9180](https://issues.apache.org/jira/browse/CB-9180) Add correct supported check for **Windows 8.1** desktop
+* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-statusbar documentation translation: cordova-plugin-statusbar
+* fix npm md issue
+
+### 1.0.0 (Apr 15, 2015)
+* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump
+* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name
+* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) properly updated translated docs to use new id
+* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id
+* Use TRAVIS_BUILD_DIR, install paramedic by npm
+* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme
+* - Use StatusBarBackgroundColor instead of AndroidStatusBarBackgroundColor, and added a quirk to the readme.
+* - Add support for StatusBar.backgroundColorByHexString (and StatusBar.backgroundColorByName) on Android 5 and up
+* Allow setting the statusbar backgroundcolor on Android
+* [CB-8575](https://issues.apache.org/jira/browse/CB-8575) Integrate TravisCI
+* [CB-8438](https://issues.apache.org/jira/browse/CB-8438) cordova-plugin-statusbar documentation translation: cordova-plugin-statusbar
+* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file
+
+### 0.1.10 (Feb 04, 2015)
+* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Use argumentForIndex rather than NSArray extension
+
+### 0.1.9 (Dec 02, 2014)
+* Fix onload attribute within <feature> to be a <param>
+* [CB-8010](https://issues.apache.org/jira/browse/CB-8010) - Statusbar colour does not change to orange
+* added checks for running on windows when StatusBar is NOT available
+* [CB-7986](https://issues.apache.org/jira/browse/CB-7986) Add cordova-plugin-statusbar support for **Windows Phone 8.1**
+* [CB-7977](https://issues.apache.org/jira/browse/CB-7977) Mention `deviceready` in plugin docs
+* [CB-7979](https://issues.apache.org/jira/browse/CB-7979) Each plugin doc should have a ## Installation section
+* Inserting leading space after # for consistency
+* [CB-7549](https://issues.apache.org/jira/browse/CB-7549) - (Re-fix) `StatusBar` **iOS 8** Landscape issue (closes #15)
+* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-statusbar documentation translation: cordova-plugin-statusbar
+* [CB-7571](https://issues.apache.org/jira/browse/CB-7571) Bump version of nested plugin to match parent plugin
+
+### 0.1.8 (Sep 17, 2014)
+* [CB-7549](https://issues.apache.org/jira/browse/CB-7549) [StatusBar][iOS 8] Landscape issue
+* [CB-7486](https://issues.apache.org/jira/browse/CB-7486) Remove StatusBarBackgroundColor intial preference (black background) so background will be initially transparent
+* Renamed test dir, added nested plugin.xml
+* added documentation for manual tests, moved background color test below overlay test
+* [CB-7195](https://issues.apache.org/jira/browse/CB-7195) ported statusbar tests to framework
+
+### 0.1.7 (Aug 06, 2014)
+* Add LICENSE and NOTICE
+* Update statusbar.js
+* Update backgroundColorByHexString function
+* ios: Use a persistent callbackId instead of calling sendJs
+* [CB-6626](https://issues.apache.org/jira/browse/CB-6626) ios: Add a JS event for tapping on statusbar
+* ios: Fix hide to adjust webview's frame only when status bar is not overlaying webview
+* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Updated translations for docs
+* android: Fix StatusBar.initialize() not running on UI thread
+
+### 0.1.6 (Jun 05, 2014)
+* [CB-6783](https://issues.apache.org/jira/browse/CB-6783) - added StatusBarStyle config preference,  updated docs (closes #9)
+* [CB-6812](https://issues.apache.org/jira/browse/CB-6812) Add license
+* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md
+* [CB-6264](https://issues.apache.org/jira/browse/CB-6264) minor formatting issue
+* Update docs with recent WP changes, remove 'clear' from the loist of named colors in documentation
+* [CB-6513](https://issues.apache.org/jira/browse/CB-6513) - Statusbar plugin for Android is not compiling
+
+### 0.1.5 (Apr 17, 2014) (First release as a core Cordova Plugin)
+* [CB-6316](https://issues.apache.org/jira/browse/CB-6316): Added README.md which point to the new location for docs
+* [CB-6316](https://issues.apache.org/jira/browse/CB-6316): Added license header to the documentation. Added README.md which point to the new location for docs
+* [CB-6316](https://issues.apache.org/jira/browse/CB-6316): Moved StatusBar plugin documentation to docs folder
+* [CB-6314](https://issues.apache.org/jira/browse/CB-6314): [android] Add StatusBar.isVisible support to Android
+* [CB-6460](https://issues.apache.org/jira/browse/CB-6460): Update license headers

+ 81 - 0
cordova/plugins/cordova-plugin-statusbar/package.json

@@ -0,0 +1,81 @@
+{
+  "_from": "cordova-plugin-statusbar@2.4.3",
+  "_id": "cordova-plugin-statusbar@2.4.3",
+  "_inBundle": false,
+  "_integrity": "sha1-zFV672bCdITg9/BFAEBA0DMh+C0=",
+  "_location": "/cordova-plugin-statusbar",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "cordova-plugin-statusbar@2.4.3",
+    "name": "cordova-plugin-statusbar",
+    "escapedName": "cordova-plugin-statusbar",
+    "rawSpec": "2.4.3",
+    "saveSpec": null,
+    "fetchSpec": "2.4.3"
+  },
+  "_requiredBy": [
+    "#DEV:/",
+    "#USER"
+  ],
+  "_resolved": "https://registry.npm.taobao.org/cordova-plugin-statusbar/download/cordova-plugin-statusbar-2.4.3.tgz",
+  "_shasum": "cc557aef66c27484e0f7f045004040d03321f82d",
+  "_spec": "cordova-plugin-statusbar@2.4.3",
+  "_where": "/Users/x/Documents/twong-h5/cordova",
+  "author": {
+    "name": "Apache Software Foundation"
+  },
+  "bugs": {
+    "url": "https://github.com/apache/cordova-plugin-statusbar/issues"
+  },
+  "bundleDependencies": false,
+  "cordova": {
+    "id": "cordova-plugin-statusbar",
+    "platforms": [
+      "android",
+      "ios",
+      "wp7",
+      "wp8",
+      "windows"
+    ]
+  },
+  "deprecated": false,
+  "description": "Cordova StatusBar Plugin",
+  "devDependencies": {
+    "jshint": "^2.6.0"
+  },
+  "engines": {
+    "cordovaDependencies": {
+      "0.1.0": {
+        "cordova": ">=3.0.0"
+      },
+      "3.0.0": {
+        "cordova": ">100"
+      }
+    }
+  },
+  "homepage": "https://github.com/apache/cordova-plugin-statusbar#readme",
+  "keywords": [
+    "cordova",
+    "statusbar",
+    "ecosystem:cordova",
+    "cordova-android",
+    "cordova-ios",
+    "cordova-wp7",
+    "cordova-wp8",
+    "cordova-windows"
+  ],
+  "license": "Apache-2.0",
+  "name": "cordova-plugin-statusbar",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/apache/cordova-plugin-statusbar.git"
+  },
+  "scripts": {
+    "jshint": "node node_modules/jshint/bin/jshint www && node node_modules/jshint/bin/jshint src && node node_modules/jshint/bin/jshint tests",
+    "test": "npm run jshint"
+  },
+  "types": "./types/index.d.ts",
+  "version": "2.4.3"
+}

+ 99 - 0
cordova/plugins/cordova-plugin-statusbar/plugin.xml

@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+    xmlns:rim="http://www.blackberry.com/ns/widgets"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    id="cordova-plugin-statusbar"
+    version="2.4.3">
+    <name>StatusBar</name>
+    <description>Cordova StatusBar Plugin</description>
+    <license>Apache 2.0</license>
+    <keywords>cordova,statusbar</keywords>
+
+    <engines>
+            <engine name="cordova" version=">=3.0.0" />
+    </engines>
+
+    <js-module src="www/statusbar.js" name="statusbar">
+        <clobbers target="window.StatusBar" />
+    </js-module>
+
+    <platform name="android">
+        <source-file src="src/android/StatusBar.java" target-dir="src/org/apache/cordova/statusbar" />
+
+        <config-file target="res/xml/config.xml" parent="/*">
+            <feature name="StatusBar">
+                <param name="android-package" value="org.apache.cordova.statusbar.StatusBar" />
+                <param name="onload" value="true" />
+            </feature>
+        </config-file>
+    </platform>
+
+    <platform name="browser">
+        <js-module src="src/browser/StatusBarProxy.js" name="StatusBarProxy">
+            <runs />
+        </js-module>
+    </platform>
+
+    <!-- ios -->
+    <platform name="ios">
+
+        <config-file target="config.xml" parent="/*">
+            <feature name="StatusBar">
+                <param name="ios-package" value="CDVStatusBar" />
+                <param name="onload" value="true" />
+            </feature>
+            <preference name="StatusBarOverlaysWebView" value="true" />
+            <preference name="StatusBarStyle" value="lightcontent" />
+        </config-file>
+
+        <header-file src="src/ios/CDVStatusBar.h" />
+        <source-file src="src/ios/CDVStatusBar.m" />
+
+    </platform>
+
+    <!-- wp7 -->
+    <platform name="wp7">
+        <config-file target="config.xml" parent="/*">
+            <feature name="StatusBar">
+                <param name="wp-package" value="StatusBar"/>
+            </feature>
+        </config-file>
+        <source-file src="src/wp/StatusBar.cs" />
+    </platform>
+
+    <!-- wp8 -->
+    <platform name="wp8">
+        <config-file target="config.xml" parent="/*">
+            <feature name="StatusBar">
+                <param name="wp-package" value="StatusBar"/>
+            </feature>
+        </config-file>
+        <source-file src="src/wp/StatusBar.cs" />
+    </platform>
+
+    <!-- windows -->
+    <platform name="windows">
+        <js-module src="src/windows/StatusBarProxy.js" name="StatusBarProxy">
+            <runs />
+        </js-module>
+    </platform>
+</plugin>

+ 276 - 0
cordova/plugins/cordova-plugin-statusbar/src/android/StatusBar.java

@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+package org.apache.cordova.statusbar;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Build;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaArgs;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginResult;
+import org.json.JSONException;
+import java.util.Arrays;
+
+public class StatusBar extends CordovaPlugin {
+    private static final String TAG = "StatusBar";
+
+    /**
+     * Sets the context of the Command. This can then be used to do things like
+     * get file paths associated with the Activity.
+     *
+     * @param cordova The context of the main Activity.
+     * @param webView The CordovaWebView Cordova is running in.
+     */
+    @Override
+    public void initialize(final CordovaInterface cordova, CordovaWebView webView) {
+        LOG.v(TAG, "StatusBar: initialization");
+        super.initialize(cordova, webView);
+
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Clear flag FLAG_FORCE_NOT_FULLSCREEN which is set initially
+                // by the Cordova.
+                Window window = cordova.getActivity().getWindow();
+                window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+
+                // Read 'StatusBarBackgroundColor' from config.xml, default is #000000.
+                setStatusBarBackgroundColor(preferences.getString("StatusBarBackgroundColor", "#000000"));
+
+                // Read 'StatusBarStyle' from config.xml, default is 'lightcontent'.
+                setStatusBarStyle(preferences.getString("StatusBarStyle", "lightcontent"));
+            }
+        });
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action            The action to execute.
+     * @param args              JSONArry of arguments for the plugin.
+     * @param callbackContext   The callback id used when calling back into JavaScript.
+     * @return                  True if the action was valid, false otherwise.
+     */
+    @Override
+    public boolean execute(final String action, final CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
+        LOG.v(TAG, "Executing action: " + action);
+        final Activity activity = this.cordova.getActivity();
+        final Window window = activity.getWindow();
+
+        if ("_ready".equals(action)) {
+            boolean statusBarVisible = (window.getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0;
+            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, statusBarVisible));
+            return true;
+        }
+
+        if ("show".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    // SYSTEM_UI_FLAG_FULLSCREEN is available since JellyBean, but we
+                    // use KitKat here to be aligned with "Fullscreen"  preference
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                        int uiOptions = window.getDecorView().getSystemUiVisibility();
+                        uiOptions &= ~View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+                        uiOptions &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+
+                        window.getDecorView().setSystemUiVisibility(uiOptions);
+                    }
+
+                    // CB-11197 We still need to update LayoutParams to force status bar
+                    // to be hidden when entering e.g. text fields
+                    window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                }
+            });
+            return true;
+        }
+
+        if ("hide".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    // SYSTEM_UI_FLAG_FULLSCREEN is available since JellyBean, but we
+                    // use KitKat here to be aligned with "Fullscreen"  preference
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                        int uiOptions = window.getDecorView().getSystemUiVisibility()
+                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                                | View.SYSTEM_UI_FLAG_FULLSCREEN;
+
+                        window.getDecorView().setSystemUiVisibility(uiOptions);
+                    }
+
+                    // CB-11197 We still need to update LayoutParams to force status bar
+                    // to be hidden when entering e.g. text fields
+                    window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                }
+            });
+            return true;
+        }
+
+        if ("backgroundColorByHexString".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        setStatusBarBackgroundColor(args.getString(0));
+                    } catch (JSONException ignore) {
+                        LOG.e(TAG, "Invalid hexString argument, use f.i. '#777777'");
+                    }
+                }
+            });
+            return true;
+        }
+
+        if ("overlaysWebView".equals(action)) {
+            if (Build.VERSION.SDK_INT >= 21) {
+                this.cordova.getActivity().runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            setStatusBarTransparent(args.getBoolean(0));
+                        } catch (JSONException ignore) {
+                            LOG.e(TAG, "Invalid boolean argument");
+                        }
+                    }
+                });
+                return true;
+            }
+            else return args.getBoolean(0) == false;
+        }
+
+        if ("styleDefault".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("default");
+                }
+            });
+            return true;
+        }
+
+        if ("styleLightContent".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("lightcontent");
+                }
+            });
+            return true;
+        }
+
+        if ("styleBlackTranslucent".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("blacktranslucent");
+                }
+            });
+            return true;
+        }
+
+        if ("styleBlackOpaque".equals(action)) {
+            this.cordova.getActivity().runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setStatusBarStyle("blackopaque");
+                }
+            });
+            return true;
+        }
+
+        return false;
+    }
+
+    private void setStatusBarBackgroundColor(final String colorPref) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            if (colorPref != null && !colorPref.isEmpty()) {
+                final Window window = cordova.getActivity().getWindow();
+                // Method and constants not available on all SDKs but we want to be able to compile this code with any SDK
+                window.clearFlags(0x04000000); // SDK 19: WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                window.addFlags(0x80000000); // SDK 21: WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+                try {
+                    // Using reflection makes sure any 5.0+ device will work without having to compile with SDK level 21
+                    window.getClass().getMethod("setStatusBarColor", int.class).invoke(window, Color.parseColor(colorPref));
+                } catch (IllegalArgumentException ignore) {
+                    LOG.e(TAG, "Invalid hexString argument, use f.i. '#999999'");
+                } catch (Exception ignore) {
+                    // this should not happen, only in case Android removes this method in a version > 21
+                    LOG.w(TAG, "Method window.setStatusBarColor not found for SDK level " + Build.VERSION.SDK_INT);
+                }
+            }
+        }
+    }
+
+    private void setStatusBarTransparent(final boolean transparent) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            final Window window = cordova.getActivity().getWindow();
+            if (transparent) {
+                window.getDecorView().setSystemUiVisibility(
+                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+                window.setStatusBarColor(Color.TRANSPARENT);
+            }
+            else {
+                window.getDecorView().setSystemUiVisibility(
+                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                                | View.SYSTEM_UI_FLAG_VISIBLE);
+            }
+        }
+    }
+
+    private void setStatusBarStyle(final String style) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            if (style != null && !style.isEmpty()) {
+                View decorView = cordova.getActivity().getWindow().getDecorView();
+                int uiOptions = decorView.getSystemUiVisibility();
+
+                String[] darkContentStyles = {
+                    "default",
+                };
+
+                String[] lightContentStyles = {
+                    "lightcontent",
+                    "blacktranslucent",
+                    "blackopaque",
+                };
+
+                if (Arrays.asList(darkContentStyles).contains(style.toLowerCase())) {
+                    decorView.setSystemUiVisibility(uiOptions | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+                    return;
+                }
+
+                if (Arrays.asList(lightContentStyles).contains(style.toLowerCase())) {
+                    decorView.setSystemUiVisibility(uiOptions & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+                    return;
+                }
+
+                LOG.e(TAG, "Invalid style, must be either 'default', 'lightcontent' or the deprecated 'blacktranslucent' and 'blackopaque'");
+            }
+        }
+    }
+}

+ 50 - 0
cordova/plugins/cordova-plugin-statusbar/src/browser/StatusBarProxy.js

@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+function notSupported(win,fail) {
+    //
+    console.log('StatusBar is not supported');
+    setTimeout(function(){
+        if (win) {
+            win();
+        }
+        // note that while it is not explicitly supported, it does not fail
+        // this is really just here to allow developers to test their code in the browser
+        // and if we fail, then their app might as well. -jm
+    },0);
+}
+
+module.exports = {
+    isVisible: false,
+    styleBlackTranslucent:notSupported,
+    styleDefault:notSupported,
+    styleLightContent:notSupported,
+    styleBlackOpaque:notSupported,
+    overlaysWebView:notSupported,
+    styleLightContect: notSupported,
+    backgroundColorByName: notSupported,
+    backgroundColorByHexString: notSupported,
+    hide: notSupported,
+    show: notSupported,
+    _ready:notSupported
+};
+
+require("cordova/exec/proxy").add("StatusBar", module.exports);
+

+ 50 - 0
cordova/plugins/cordova-plugin-statusbar/src/ios/CDVStatusBar.h

@@ -0,0 +1,50 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Cordova/CDVPlugin.h>
+#import <Cordova/CDVInvokedUrlCommand.h>
+
+@interface CDVStatusBar : CDVPlugin {
+    @protected
+    BOOL _statusBarOverlaysWebView;
+    UIView* _statusBarBackgroundView;
+    BOOL _uiviewControllerBasedStatusBarAppearance;
+    UIColor* _statusBarBackgroundColor;
+    NSString* _eventsCallbackId;
+}
+
+@property (atomic, assign) BOOL statusBarOverlaysWebView;
+@property (atomic, assign) BOOL statusBarVisible;
+
+- (void) overlaysWebView:(CDVInvokedUrlCommand*)command;
+
+- (void) styleDefault:(CDVInvokedUrlCommand*)command;
+- (void) styleLightContent:(CDVInvokedUrlCommand*)command;
+- (void) styleBlackTranslucent:(CDVInvokedUrlCommand*)command;
+- (void) styleBlackOpaque:(CDVInvokedUrlCommand*)command;
+
+- (void) backgroundColorByName:(CDVInvokedUrlCommand*)command;
+- (void) backgroundColorByHexString:(CDVInvokedUrlCommand*)command;
+
+- (void) hide:(CDVInvokedUrlCommand*)command;
+- (void) show:(CDVInvokedUrlCommand*)command;
+    
+- (void) _ready:(CDVInvokedUrlCommand*)command;
+
+@end

+ 479 - 0
cordova/plugins/cordova-plugin-statusbar/src/ios/CDVStatusBar.m

@@ -0,0 +1,479 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+/*
+ NOTE: plugman/cordova cli should have already installed this,
+ but you need the value UIViewControllerBasedStatusBarAppearance
+ in your Info.plist as well to set the styles in iOS 7
+ */
+
+#import "CDVStatusBar.h"
+#import <objc/runtime.h>
+#import <Cordova/CDVViewController.h>
+
+static const void *kHideStatusBar = &kHideStatusBar;
+static const void *kStatusBarStyle = &kStatusBarStyle;
+
+@interface CDVViewController (StatusBar)
+
+@property (nonatomic, retain) id sb_hideStatusBar;
+@property (nonatomic, retain) id sb_statusBarStyle;
+
+@end
+
+@implementation CDVViewController (StatusBar)
+
+@dynamic sb_hideStatusBar;
+@dynamic sb_statusBarStyle;
+
+- (id)sb_hideStatusBar {
+    return objc_getAssociatedObject(self, kHideStatusBar);
+}
+
+- (void)setSb_hideStatusBar:(id)newHideStatusBar {
+    objc_setAssociatedObject(self, kHideStatusBar, newHideStatusBar, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (id)sb_statusBarStyle {
+    return objc_getAssociatedObject(self, kStatusBarStyle);
+}
+
+- (void)setSb_statusBarStyle:(id)newStatusBarStyle {
+    objc_setAssociatedObject(self, kStatusBarStyle, newStatusBarStyle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (BOOL) prefersStatusBarHidden {
+    return [self.sb_hideStatusBar boolValue];
+}
+
+- (UIStatusBarStyle)preferredStatusBarStyle
+{
+    return (UIStatusBarStyle)[self.sb_statusBarStyle intValue];
+}
+
+@end
+
+
+@interface CDVStatusBar () <UIScrollViewDelegate>
+- (void)fireTappedEvent;
+- (void)updateIsVisible:(BOOL)visible;
+@end
+
+@implementation CDVStatusBar
+
+- (id)settingForKey:(NSString*)key
+{
+    return [self.commandDelegate.settings objectForKey:[key lowercaseString]];
+}
+
+- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
+{
+    if ([keyPath isEqual:@"statusBarHidden"]) {
+        NSNumber* newValue = [change objectForKey:NSKeyValueChangeNewKey];
+        [self updateIsVisible:![newValue boolValue]];
+    }
+}
+
+-(void)cordovaViewWillAppear:(NSNotification*)notification
+{
+    [self resizeWebView];
+}
+
+-(void)statusBarDidChangeFrame:(NSNotification*)notification
+{
+    //add a small delay ( 0.1 seconds ) or statusbar size will be wrong
+    __weak CDVStatusBar* weakSelf = self;
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+        [weakSelf resizeStatusBarBackgroundView];
+        [weakSelf resizeWebView];
+    });
+}
+
+- (void)pluginInitialize
+{
+    // init
+    NSNumber* uiviewControllerBasedStatusBarAppearance = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"];
+    _uiviewControllerBasedStatusBarAppearance = (uiviewControllerBasedStatusBarAppearance == nil || [uiviewControllerBasedStatusBarAppearance boolValue]);
+
+    // observe the statusBarHidden property
+    [[UIApplication sharedApplication] addObserver:self forKeyPath:@"statusBarHidden" options:NSKeyValueObservingOptionNew context:NULL];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarDidChangeFrame:) name: UIApplicationDidChangeStatusBarFrameNotification object:nil];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cordovaViewWillAppear:) name: @"CDVViewWillAppearNotification" object:nil];
+
+    _statusBarOverlaysWebView = YES; // default
+
+    [self initializeStatusBarBackgroundView];
+
+    self.viewController.view.autoresizesSubviews = YES;
+
+    NSString* setting;
+
+    setting  = @"StatusBarBackgroundColor";
+    if ([self settingForKey:setting]) {
+        [self _backgroundColorByHexString:[self settingForKey:setting]];
+    }
+
+    setting  = @"StatusBarStyle";
+    if ([self settingForKey:setting]) {
+        [self setStatusBarStyle:[self settingForKey:setting]];
+    }
+
+    setting  = @"StatusBarDefaultScrollToTop";
+    if ([self settingForKey:setting]) {
+        self.webView.scrollView.scrollsToTop = [(NSNumber*)[self settingForKey:setting] boolValue];
+    } else {
+        self.webView.scrollView.scrollsToTop = NO;
+    }
+ 
+    // blank scroll view to intercept status bar taps
+    UIScrollView *fakeScrollView = [[UIScrollView alloc] initWithFrame:UIScreen.mainScreen.bounds];
+    fakeScrollView.delegate = self;
+    fakeScrollView.scrollsToTop = YES;
+    [self.viewController.view addSubview:fakeScrollView]; // Add scrollview to the view heirarchy so that it will begin accepting status bar taps
+    [self.viewController.view sendSubviewToBack:fakeScrollView]; // Send it to the very back of the view heirarchy
+    fakeScrollView.contentSize = CGSizeMake(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height * 2.0f); // Make the scroll view longer than the screen itself
+    fakeScrollView.contentOffset = CGPointMake(0.0f, UIScreen.mainScreen.bounds.size.height); // Scroll down so a tap will take scroll view back to the top
+
+    _statusBarVisible = ![UIApplication sharedApplication].isStatusBarHidden;
+}
+
+- (void)onReset {
+    _eventsCallbackId = nil;
+}
+
+- (void)fireTappedEvent {
+    if (_eventsCallbackId == nil) {
+        return;
+    }
+    NSDictionary* payload = @{@"type": @"tap"};
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:payload];
+    [result setKeepCallbackAsBool:YES];
+    [self.commandDelegate sendPluginResult:result callbackId:_eventsCallbackId];
+}
+
+- (void)updateIsVisible:(BOOL)visible {
+    if (_eventsCallbackId == nil) {
+        return;
+    }
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:visible];
+    [result setKeepCallbackAsBool:YES];
+    [self.commandDelegate sendPluginResult:result callbackId:_eventsCallbackId];
+}
+
+- (void) _ready:(CDVInvokedUrlCommand*)command
+{
+    _eventsCallbackId = command.callbackId;
+    [self updateIsVisible:![UIApplication sharedApplication].statusBarHidden];
+    NSString* setting = @"StatusBarOverlaysWebView";
+    if ([self settingForKey:setting]) {
+        self.statusBarOverlaysWebView = [(NSNumber*)[self settingForKey:setting] boolValue];
+        if (self.statusBarOverlaysWebView) {
+            [self resizeWebView];
+        }
+    }
+}
+
+- (void) initializeStatusBarBackgroundView
+{
+    CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
+
+    if ([[UIApplication sharedApplication]statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown &&
+        statusBarFrame.size.height + statusBarFrame.origin.y == [self.viewController.view.window bounds].size.height) {
+
+        // When started in upside-down orientation on iOS 7, status bar will be bound to lower edge of the
+        // screen (statusBarFrame.origin.y will be somewhere around screen height). In this case we need to
+        // correct frame's coordinates
+        statusBarFrame.origin.y = 0;
+    }
+
+    _statusBarBackgroundView = [[UIView alloc] initWithFrame:statusBarFrame];
+    _statusBarBackgroundView.backgroundColor = _statusBarBackgroundColor;
+    _statusBarBackgroundView.autoresizingMask = (UIViewAutoresizingFlexibleWidth  | UIViewAutoresizingFlexibleBottomMargin);
+    _statusBarBackgroundView.autoresizesSubviews = YES;
+}
+
+- (void) setStatusBarOverlaysWebView:(BOOL)statusBarOverlaysWebView
+{
+    // we only care about the latest iOS version or a change in setting
+    if (statusBarOverlaysWebView == _statusBarOverlaysWebView) {
+        return;
+    }
+
+    _statusBarOverlaysWebView = statusBarOverlaysWebView;
+
+    [self resizeWebView];
+
+    if (statusBarOverlaysWebView) {
+
+        [_statusBarBackgroundView removeFromSuperview];
+
+    } else {
+
+        [self initializeStatusBarBackgroundView];
+        [self.webView.superview addSubview:_statusBarBackgroundView];
+
+    }
+
+}
+
+- (BOOL) statusBarOverlaysWebView
+{
+    return _statusBarOverlaysWebView;
+}
+
+- (void) overlaysWebView:(CDVInvokedUrlCommand*)command
+{
+    id value = [command argumentAtIndex:0];
+    if (!([value isKindOfClass:[NSNumber class]])) {
+        value = [NSNumber numberWithBool:YES];
+    }
+
+    self.statusBarOverlaysWebView = [value boolValue];
+}
+
+- (void) refreshStatusBarAppearance
+{
+    SEL sel = NSSelectorFromString(@"setNeedsStatusBarAppearanceUpdate");
+    if ([self.viewController respondsToSelector:sel]) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        [self.viewController performSelector:sel withObject:nil];
+#pragma clang diagnostic pop
+    }
+}
+
+- (void) setStyleForStatusBar:(UIStatusBarStyle)style
+{
+    if (_uiviewControllerBasedStatusBarAppearance) {
+        CDVViewController* vc = (CDVViewController*)self.viewController;
+        vc.sb_statusBarStyle = [NSNumber numberWithInt:style];
+        [self refreshStatusBarAppearance];
+
+    } else {
+        [[UIApplication sharedApplication] setStatusBarStyle:style];
+    }
+}
+
+- (void) setStatusBarStyle:(NSString*)statusBarStyle
+{
+    // default, lightContent, blackTranslucent, blackOpaque
+    NSString* lcStatusBarStyle = [statusBarStyle lowercaseString];
+
+    if ([lcStatusBarStyle isEqualToString:@"default"]) {
+        [self styleDefault:nil];
+    } else if ([lcStatusBarStyle isEqualToString:@"lightcontent"]) {
+        [self styleLightContent:nil];
+    } else if ([lcStatusBarStyle isEqualToString:@"blacktranslucent"]) {
+        [self styleBlackTranslucent:nil];
+    } else if ([lcStatusBarStyle isEqualToString:@"blackopaque"]) {
+        [self styleBlackOpaque:nil];
+    }
+}
+
+- (void) styleDefault:(CDVInvokedUrlCommand*)command
+{
+    [self setStyleForStatusBar:UIStatusBarStyleDefault];
+}
+
+- (void) styleLightContent:(CDVInvokedUrlCommand*)command
+{
+    [self setStyleForStatusBar:UIStatusBarStyleLightContent];
+}
+
+- (void) styleBlackTranslucent:(CDVInvokedUrlCommand*)command
+{
+    [self setStyleForStatusBar:UIStatusBarStyleLightContent];
+}
+
+- (void) styleBlackOpaque:(CDVInvokedUrlCommand*)command
+{
+    [self setStyleForStatusBar:UIStatusBarStyleLightContent];
+}
+
+- (void) backgroundColorByName:(CDVInvokedUrlCommand*)command
+{
+    id value = [command argumentAtIndex:0];
+    if (!([value isKindOfClass:[NSString class]])) {
+        value = @"black";
+    }
+
+    SEL selector = NSSelectorFromString([value stringByAppendingString:@"Color"]);
+    if ([UIColor respondsToSelector:selector]) {
+        _statusBarBackgroundView.backgroundColor = [UIColor performSelector:selector];
+    }
+}
+
+- (void) _backgroundColorByHexString:(NSString*)hexString
+{
+    unsigned int rgbValue = 0;
+    NSScanner* scanner = [NSScanner scannerWithString:hexString];
+    [scanner setScanLocation:1];
+    [scanner scanHexInt:&rgbValue];
+
+    _statusBarBackgroundColor = [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
+    _statusBarBackgroundView.backgroundColor = _statusBarBackgroundColor;
+}
+
+- (void) backgroundColorByHexString:(CDVInvokedUrlCommand*)command
+{
+    NSString* value = [command argumentAtIndex:0];
+    if (!([value isKindOfClass:[NSString class]])) {
+        value = @"#000000";
+    }
+
+    if (![value hasPrefix:@"#"] || [value length] < 7) {
+        return;
+    }
+
+    [self _backgroundColorByHexString:value];
+}
+
+- (void) hideStatusBar
+{
+    if (_uiviewControllerBasedStatusBarAppearance) {
+        CDVViewController* vc = (CDVViewController*)self.viewController;
+        vc.sb_hideStatusBar = [NSNumber numberWithBool:YES];
+        [self refreshStatusBarAppearance];
+
+    } else {
+        UIApplication* app = [UIApplication sharedApplication];
+        [app setStatusBarHidden:YES];
+    }
+}
+
+- (void) hide:(CDVInvokedUrlCommand*)command
+{
+    _statusBarVisible = NO;
+    UIApplication* app = [UIApplication sharedApplication];
+
+    if (!app.isStatusBarHidden)
+    {
+
+        [self hideStatusBar];
+
+        [_statusBarBackgroundView removeFromSuperview];
+
+        [self resizeWebView];
+
+        _statusBarBackgroundView.hidden = YES;
+    }
+}
+
+- (void) showStatusBar
+{
+    if (_uiviewControllerBasedStatusBarAppearance) {
+        CDVViewController* vc = (CDVViewController*)self.viewController;
+        vc.sb_hideStatusBar = [NSNumber numberWithBool:NO];
+        [self refreshStatusBarAppearance];
+
+    } else {
+        UIApplication* app = [UIApplication sharedApplication];
+        [app setStatusBarHidden:NO];
+    }
+}
+
+- (void) show:(CDVInvokedUrlCommand*)command
+{
+    _statusBarVisible = YES;
+    UIApplication* app = [UIApplication sharedApplication];
+
+    if (app.isStatusBarHidden)
+    {
+        [self showStatusBar];
+        [self resizeWebView];
+
+        if (!self.statusBarOverlaysWebView) {
+
+            // there is a possibility that when the statusbar was hidden, it was in a different orientation
+            // from the current one. Therefore we need to expand the statusBarBackgroundView as well to the
+            // statusBar's current size
+            [self resizeStatusBarBackgroundView];
+            [self.webView.superview addSubview:_statusBarBackgroundView];
+
+        }
+
+        _statusBarBackgroundView.hidden = NO;
+    }
+}
+
+-(void)resizeStatusBarBackgroundView {
+    CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
+    CGRect sbBgFrame = _statusBarBackgroundView.frame;
+    sbBgFrame.size = statusBarFrame.size;
+    _statusBarBackgroundView.frame = sbBgFrame;
+}
+
+-(void)resizeWebView
+{
+    BOOL isIOS11 = (IsAtLeastiOSVersion(@"11.0"));
+
+    CGRect bounds = [self.viewController.view.window bounds];
+    if (CGRectEqualToRect(bounds, CGRectZero)) {
+        bounds = [[UIScreen mainScreen] bounds];
+    }
+
+    self.viewController.view.frame = bounds;
+
+    self.webView.frame = bounds;
+
+    CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
+    CGRect frame = self.webView.frame;
+    CGFloat height = statusBarFrame.size.height;
+
+    if (!self.statusBarOverlaysWebView) {
+        frame.origin.y = height;
+    } else {
+        frame.origin.y = height >= 20 ? height - 20 : 0;
+        if (isIOS11) {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+            if (@available(iOS 11.0, *)) {
+                float safeAreaTop = self.webView.safeAreaInsets.top;
+                if (height >= safeAreaTop && safeAreaTop >0) {
+                    // Sometimes when in-call/recording/hotspot larger status bar is present, the safeAreaTop is 40 but we want frame.origin.y to be 20
+                    frame.origin.y = safeAreaTop == 40 ? 20 : height - safeAreaTop;
+                } else {
+                    frame.origin.y = 0;
+                }
+            }
+#endif
+        }
+    }
+    frame.size.height -= frame.origin.y;
+    self.webView.frame = frame;
+    
+}
+
+- (void) dealloc
+{
+    [[UIApplication sharedApplication] removeObserver:self forKeyPath:@"statusBarHidden"];
+    [[NSNotificationCenter defaultCenter]removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
+}
+
+
+#pragma mark - UIScrollViewDelegate
+
+- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
+{
+    [self fireTappedEvent];
+    return NO;
+}
+
+@end

+ 114 - 0
cordova/plugins/cordova-plugin-statusbar/src/windows/StatusBarProxy.js

@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/* global Windows */
+
+var _supported = null; // set to null so we can check first time
+
+function isSupported() {
+    // if not checked before, run check
+    if (_supported === null) {
+        var viewMan = Windows.UI.ViewManagement; 
+        _supported = (viewMan.StatusBar && viewMan.StatusBar.getForCurrentView);
+    }
+    return _supported;
+}
+
+function getViewStatusBar() {
+    if (!isSupported()) {
+        throw new Error("Status bar is not supported");
+    }
+    return Windows.UI.ViewManagement.StatusBar.getForCurrentView();
+}
+
+function hexToRgb(hex) {
+    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
+    var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+    hex = hex.replace(shorthandRegex, function (m, r, g, b) {
+        return r + r + g + g + b + b;
+    });
+
+    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+    return result ? {
+        r: parseInt(result[1], 16),
+        g: parseInt(result[2], 16),
+        b: parseInt(result[3], 16)
+    } : null;
+}
+
+module.exports = {
+    _ready: function(win, fail) {
+        if(isSupported()) {
+            var statusBar = getViewStatusBar();
+            win(statusBar.occludedRect.height !== 0);
+        }
+    },
+    overlaysWebView: function () {
+        // not supported
+    },
+
+    styleDefault: function () {
+        // dark text ( to be used on a light background )
+        if (isSupported()) {
+            getViewStatusBar().foregroundColor = { a: 0, r: 0, g: 0, b: 0 };
+        }
+    },
+
+    styleLightContent: function () {
+        // light text ( to be used on a dark background )
+        if (isSupported()) {
+            getViewStatusBar().foregroundColor = { a: 0, r: 255, g: 255, b: 255 };
+        }
+    },
+
+    styleBlackTranslucent: function () {
+        // #88000000 ? Apple says to use lightContent instead
+        return module.exports.styleLightContent();
+    },
+
+    styleBlackOpaque: function () {
+        // #FF000000 ? Apple says to use lightContent instead
+        return module.exports.styleLightContent();
+    },
+
+    backgroundColorByHexString: function (win, fail, args) {
+        var rgb = hexToRgb(args[0]);
+        if(isSupported()) {
+            var statusBar = getViewStatusBar();
+            statusBar.backgroundColor = { a: 0, r: rgb.r, g: rgb.g, b: rgb.b };
+            statusBar.backgroundOpacity = 1;
+        }
+    },
+
+    show: function (win, fail) {
+        // added support check so no error thrown, when calling this method
+        if (isSupported()) {
+            getViewStatusBar().showAsync().done(win, fail);
+        }
+    },
+
+    hide: function (win, fail) {
+        // added support check so no error thrown, when calling this method
+        if (isSupported()) {
+            getViewStatusBar().hideAsync().done(win, fail);
+        }
+    }
+};
+require("cordova/exec/proxy").add("StatusBar", module.exports);

Some files were not shown because too many files changed in this diff