ios.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. var mappings = require("./mappings"),
  2. platformName = "ios",
  3. platformDir = 'platforms/ios/',
  4. xcodeprojRegex = /\.xcodeproj$/i;
  5. module.exports = function (Q, fs, path, plist, xcode) {
  6. function mapConfig(config) {
  7. var element = {};
  8. if (!config.type) {
  9. throw "no type defined for "+JSON.stringify (config, null, "\t");
  10. }
  11. var mapping = mappings[config.type];
  12. if (!mapping)
  13. throw "no mapping for "+ config.type;
  14. element.Type = mapping[platformName];
  15. if (mapping.required) {
  16. mapping.required.forEach (function (k) {
  17. if (!(k in config)) {
  18. throw 'ERROR: attribute "'+ k + '" not found for ' + config.title + ' (type: ' + config.type + ')';
  19. }
  20. });
  21. }
  22. if (mapping.attrs) {
  23. for (var attrName in mapping.attrs) {
  24. if (!config.hasOwnProperty(attrName))
  25. continue;
  26. var attrConfig = mapping.attrs[attrName];
  27. var elementKey = attrConfig[platformName];
  28. if (attrConfig.value) {
  29. if (!attrConfig.value[config[attrName]] || !attrConfig.value[config[attrName]][platformName])
  30. throw "no mapping for type: "+ config.type + ", attr: " + attrName + ", value: " + config[attrName];
  31. element[elementKey] = attrConfig.value[config[attrName]][platformName];
  32. } else {
  33. element[elementKey] = config[attrName];
  34. }
  35. }
  36. }
  37. if (mapping.fixup && mapping.fixup[platformName]) {
  38. mapping.fixup[platformName] (element, config, mapping);
  39. }
  40. return element;
  41. }
  42. // build iOS settings bundle
  43. function buildItems(data) {
  44. var items = [];
  45. for (var i=0, l=data.length; i<l; i++) {
  46. var src = data[i];
  47. items.push(mapConfig(src));
  48. if (src.type == 'group') {
  49. src.items.forEach(function(s) {
  50. items.push(mapConfig(s));
  51. });
  52. }
  53. }
  54. return items;
  55. }
  56. function parseXCode(projPath) {
  57. var proj = xcode.project(projPath);
  58. proj.parseSync();
  59. return proj;
  60. }
  61. function buildXCode() {
  62. // console.log ('searching for xcodeproj:', process.cwd(), platformDir, xcodeprojRegex);
  63. return fs.find(platformDir, xcodeprojRegex).then(function(projPath) {
  64. projPath = path.join(projPath, "project.pbxproj");
  65. var xcproj = parseXCode (projPath);
  66. xcproj.addResourceFile('Settings.bundle', {sourceTree: "SOURCE_ROOT"});
  67. var contents = xcproj.writeSync();
  68. return fs.writeFile(projPath, contents);
  69. });
  70. }
  71. function cleanXCode() {
  72. return fs.find(platformDir, xcodeprojRegex).then(function(projPath) {
  73. projPath = path.join(projPath, "project.pbxproj");
  74. var xcproj = parseXCode (projPath);
  75. xcproj.removeResourceFile ('Settings.bundle', {sourceTree: "SOURCE_ROOT"});
  76. var contents = xcproj.writeSync();
  77. return fs.writeFile(projPath, contents);
  78. });
  79. }
  80. function build(config) {
  81. var plistXml = plist.build({ PreferenceSpecifiers: buildItems(config) });
  82. return fs.exists('platforms/ios')
  83. // Check if Settings.bundle is generated by plugin
  84. .then (function () {
  85. return fs.exists ('platforms/ios/Settings.bundle')
  86. }, function (err) {
  87. if (err.code === "NEXIST") throw "no-platform"; throw err;
  88. })
  89. .then (function () {
  90. return fs.exists ('platforms/ios/Settings.bundle/.me.apla.apppreferences');
  91. }, function () {return true;})
  92. // Write settings plist
  93. .then(function () {
  94. return fs.mkdir('platforms/ios/Settings.bundle');
  95. }, function (err) {throw "incompatible";})
  96. .then(function () {
  97. return fs.writeFile('platforms/ios/Settings.bundle/.me.apla.apppreferences', "");
  98. })
  99. .then(function () {return fs.writeFile('platforms/ios/Settings.bundle/Root.plist', plistXml); })
  100. // Write localization resource file
  101. .then(function () {return fs.mkdir('platforms/ios/Settings.bundle/en.lproj'); })
  102. .then(function () {return fs.writeFile('platforms/ios/Settings.bundle/en.lproj/Root.strings', '/* */'); })
  103. // Add Settings plist to xcodeproj
  104. .then(buildXCode)
  105. .then(function () {console.log('ios settings bundle was successfully generated'); })
  106. .catch(function (err) {
  107. console.log ('error', err);
  108. if (err === "no-platform") {
  109. console.log ("Platform ios not found: skipping");
  110. return;
  111. } else if (err === "incompatible") {
  112. throw "Settings.bundle already exists and not generated by plugin. Please remove Settings.bundle from platforms/ios or app-settings.json from project root.";
  113. //} else if (err.code === 'NEXIST') {
  114. // console.log ("Platform ios not found: skipping", Object.keys (err));
  115. // return;
  116. }
  117. throw err;
  118. });
  119. }
  120. function clean(config) {
  121. return fs.exists('platforms/ios')
  122. // Check if Settings.bundle is generated by plugin
  123. .then (function () { return fs.exists ('platforms/ios/Settings.bundle/.me.apla.apppreferences'); })
  124. // Remove settings plist
  125. .then(function () { return fs.unlink('platforms/ios/Settings.bundle/Root.plist'); }, function (err) {if (err.code === "NEXIST") throw "incompatible"; throw err; })
  126. .then(function () { return fs.unlink('platforms/ios/Settings.bundle/.me.apla.apppreferences'); })
  127. // Remove localization resource file
  128. .then(function () { return fs.unlink('platforms/ios/Settings.bundle/en.lproj/Root.strings', '/* */'); })
  129. // Remove directories
  130. .then(function () { return fs.rmdir('platforms/ios/Settings.bundle/en.lproj'); })
  131. .then(function () { return fs.rmdir('platforms/ios/Settings.bundle'); })
  132. // Remove Settings plist from xcodeproj
  133. .then(cleanXCode)
  134. .then(function () { console.log('ios settings bundle was successfully cleaned'); })
  135. .catch(function (err) {
  136. if (err === "incompatible") {
  137. console.log ("Settings.bundle is generated by external tool, skipping");
  138. //} else if (err.code === 'NEXIST') {
  139. // console.log("Platform ios not found: skipping");
  140. return;
  141. }
  142. throw err;
  143. });
  144. }
  145. return {
  146. mapConfig: mapConfig,
  147. buildItems: buildItems,
  148. build: build,
  149. clean: clean
  150. };
  151. };