You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xcodePreferences.js 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. Script activates support for Universal Links in the application by setting proper preferences in the xcode project file.
  3. Which is:
  4. - deployment target set to iOS 9.0
  5. - .entitlements file added to project PBXGroup and PBXFileReferences section
  6. - path to .entitlements file added to Code Sign Entitlements preference
  7. */
  8. var path = require('path');
  9. var compare = require('node-version-compare');
  10. var ConfigXmlHelper = require('../configXmlHelper.js');
  11. var IOS_DEPLOYMENT_TARGET = '8.0';
  12. var COMMENT_KEY = /_comment$/;
  13. var context;
  14. module.exports = {
  15. enableAssociativeDomainsCapability: enableAssociativeDomainsCapability
  16. }
  17. // region Public API
  18. /**
  19. * Activate associated domains capability for the application.
  20. *
  21. * @param {Object} cordovaContext - cordova context object
  22. */
  23. function enableAssociativeDomainsCapability(cordovaContext) {
  24. context = cordovaContext;
  25. var projectFile = loadProjectFile();
  26. // adjust preferences
  27. activateAssociativeDomains(projectFile.xcode);
  28. // add entitlements file to pbxfilereference
  29. addPbxReference(projectFile.xcode);
  30. // save changes
  31. projectFile.write();
  32. }
  33. // endregion
  34. // region Alter project file preferences
  35. /**
  36. * Activate associated domains support in the xcode project file:
  37. * - set deployment target to ios 9;
  38. * - add .entitlements file to Code Sign Entitlements preference.
  39. *
  40. * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance
  41. */
  42. function activateAssociativeDomains(xcodeProject) {
  43. var configurations = nonComments(xcodeProject.pbxXCBuildConfigurationSection());
  44. var entitlementsFilePath = pathToEntitlementsFile();
  45. var config;
  46. var buildSettings;
  47. var deploymentTargetIsUpdated;
  48. for (config in configurations) {
  49. buildSettings = configurations[config].buildSettings;
  50. buildSettings['CODE_SIGN_ENTITLEMENTS'] = '"' + entitlementsFilePath + '"';
  51. // if deployment target is less then the required one - increase it
  52. if (buildSettings['IPHONEOS_DEPLOYMENT_TARGET']) {
  53. if (compare(buildSettings['IPHONEOS_DEPLOYMENT_TARGET'], IOS_DEPLOYMENT_TARGET) == -1) {
  54. buildSettings['IPHONEOS_DEPLOYMENT_TARGET'] = IOS_DEPLOYMENT_TARGET;
  55. deploymentTargetIsUpdated = true;
  56. }
  57. } else {
  58. buildSettings['IPHONEOS_DEPLOYMENT_TARGET'] = IOS_DEPLOYMENT_TARGET;
  59. deploymentTargetIsUpdated = true;
  60. }
  61. }
  62. if (deploymentTargetIsUpdated) {
  63. console.log('IOS project now has deployment target set as: ' + IOS_DEPLOYMENT_TARGET);
  64. }
  65. console.log('IOS project Code Sign Entitlements now set to: ' + entitlementsFilePath);
  66. }
  67. // endregion
  68. // region PBXReference methods
  69. /**
  70. * Add .entitlemets file into the project.
  71. *
  72. * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance
  73. */
  74. function addPbxReference(xcodeProject) {
  75. var fileReferenceSection = nonComments(xcodeProject.pbxFileReferenceSection());
  76. var entitlementsFileName = path.basename(pathToEntitlementsFile());
  77. if (isPbxReferenceAlreadySet(fileReferenceSection, entitlementsFileName)) {
  78. console.log('Entitlements file is in reference section.');
  79. return;
  80. }
  81. console.log('Entitlements file is not in references section, adding it');
  82. xcodeProject.addResourceFile(entitlementsFileName);
  83. }
  84. /**
  85. * Check if .entitlemets file reference already set.
  86. *
  87. * @param {Object} fileReferenceSection - PBXFileReference section
  88. * @param {String} entitlementsRelativeFilePath - relative path to entitlements file
  89. * @return true - if reference is set; otherwise - false
  90. */
  91. function isPbxReferenceAlreadySet(fileReferenceSection, entitlementsRelativeFilePath) {
  92. var isAlreadyInReferencesSection = false;
  93. var uuid;
  94. var fileRefEntry;
  95. for (uuid in fileReferenceSection) {
  96. fileRefEntry = fileReferenceSection[uuid];
  97. if (fileRefEntry.path && fileRefEntry.path.indexOf(entitlementsRelativeFilePath) > -1) {
  98. isAlreadyInReferencesSection = true;
  99. break;
  100. }
  101. }
  102. return isAlreadyInReferencesSection;
  103. }
  104. // region Xcode project file helpers
  105. /**
  106. * Load iOS project file from platform specific folder.
  107. *
  108. * @return {Object} projectFile - project file information
  109. */
  110. function loadProjectFile() {
  111. var platform_ios;
  112. var projectFile;
  113. try {
  114. // try pre-5.0 cordova structure
  115. platform_ios = context.requireCordovaModule('cordova-lib/src/plugman/platforms')['ios'];
  116. projectFile = platform_ios.parseProjectFile(iosPlatformPath());
  117. } catch (e) {
  118. try {
  119. // let's try cordova 5.0 structure
  120. platform_ios = context.requireCordovaModule('cordova-lib/src/plugman/platforms/ios');
  121. projectFile = platform_ios.parseProjectFile(iosPlatformPath());
  122. } catch (e) {
  123. // Then cordova 7.0
  124. var project_files = context.requireCordovaModule('glob').sync(path.join(iosPlatformPath(), '*.xcodeproj', 'project.pbxproj'));
  125. if (project_files.length === 0) {
  126. throw new Error('does not appear to be an xcode project (no xcode project file)');
  127. }
  128. var pbxPath = project_files[0];
  129. var xcodeproj = context.requireCordovaModule('xcode').project(pbxPath);
  130. xcodeproj.parseSync();
  131. projectFile = {
  132. 'xcode': xcodeproj,
  133. write: function () {
  134. var fs = context.requireCordovaModule('fs');
  135. var frameworks_file = path.join(iosPlatformPath(), 'frameworks.json');
  136. var frameworks = {};
  137. try {
  138. frameworks = context.requireCordovaModule(frameworks_file);
  139. } catch (e) { }
  140. fs.writeFileSync(pbxPath, xcodeproj.writeSync());
  141. if (Object.keys(frameworks).length === 0){
  142. // If there is no framework references remain in the project, just remove this file
  143. context.requireCordovaModule('shelljs').rm('-rf', frameworks_file);
  144. return;
  145. }
  146. fs.writeFileSync(frameworks_file, JSON.stringify(this.frameworks, null, 4));
  147. }
  148. };
  149. }
  150. }
  151. return projectFile;
  152. }
  153. /**
  154. * Remove comments from the file.
  155. *
  156. * @param {Object} obj - file object
  157. * @return {Object} file object without comments
  158. */
  159. function nonComments(obj) {
  160. var keys = Object.keys(obj);
  161. var newObj = {};
  162. for (var i = 0, len = keys.length; i < len; i++) {
  163. if (!COMMENT_KEY.test(keys[i])) {
  164. newObj[keys[i]] = obj[keys[i]];
  165. }
  166. }
  167. return newObj;
  168. }
  169. // endregion
  170. // region Path helpers
  171. function iosPlatformPath() {
  172. return path.join(projectRoot(), 'platforms', 'ios');
  173. }
  174. function projectRoot() {
  175. return context.opts.projectRoot;
  176. }
  177. function pathToEntitlementsFile() {
  178. var configXmlHelper = new ConfigXmlHelper(context),
  179. projectName = configXmlHelper.getProjectName(),
  180. fileName = projectName + '.entitlements';
  181. return path.join(projectName, 'Resources', fileName);
  182. }
  183. // endregion