Пользовательский плагин Cordova: добавьте фреймворк к «встроенным двоичным файлам»

В пользовательском плагине Cordova, как я могу настроить конкретный файл .framework в файле plugin.xml, чтобы он был добавлен в раздел «Встроенные двоичные файлы» в Xcode? Если это невозможно в настоящее время непосредственно в plugin.xml, я открыт для альтернативных предложений.

4 Solutions collect form web for “Пользовательский плагин Cordova: добавьте фреймворк к «встроенным двоичным файлам»”

Я реализовал обходное решение, пока оно не будет поддерживаться plugin.xml Cordova, надеюсь, в будущем, как только свойство embed в таких записях будет иметь такой же эффект: <framework embed="true" src="..." /> , на данный момент это свойство не помогает, следовательно, следующее обходное решение.

Следующее решение работало с использованием Кордовы версии 5.3.3.

Во-первых, обязательно добавьте запись фрейма в plugin.xml:

 <framework src="pointToYour/File.framework" embed="true" /> 

embed="true" теперь не работает, но добавьте его в любом случае.

Мы собираемся создать крючок, объявим, что в вашем plugin.xml:

 <hook type="after_platform_add" src="hooks/embedframework/addEmbedded.js" /> 

Далее, есть специальный модуль узла, который нам понадобится в коде нашего крючка, этот модуль – node-xcode .

Установите node-xcode (должна быть версия 0.8.7 или выше):

 npm i xcode 

Наконец, код самого крючка –

Файл addEmbedded.js:

 'use strict'; const xcode = require('xcode'), fs = require('fs'), path = require('path'); module.exports = function(context) { if(process.length >=5 && process.argv[1].indexOf('cordova') == -1) { if(process.argv[4] != 'ios') { return; // plugin only meant to work for ios platform. } } function fromDir(startPath,filter, rec, multiple){ if (!fs.existsSync(startPath)){ console.log("no dir ", startPath); return; } const files=fs.readdirSync(startPath); var resultFiles = [] for(var i=0;i<files.length;i++){ var filename=path.join(startPath,files[i]); var stat = fs.lstatSync(filename); if (stat.isDirectory() && rec){ fromDir(filename,filter); //recurse } if (filename.indexOf(filter)>=0) { if (multiple) { resultFiles.push(filename); } else { return filename; } } } if(multiple) { return resultFiles; } } function getFileIdAndRemoveFromFrameworks(myProj, fileBasename) { var fileId = ''; const pbxFrameworksBuildPhaseObjFiles = myProj.pbxFrameworksBuildPhaseObj(myProj.getFirstTarget().uuid).files; for(var i=0; i<pbxFrameworksBuildPhaseObjFiles.length;i++) { var frameworkBuildPhaseFile = pbxFrameworksBuildPhaseObjFiles[i]; if(frameworkBuildPhaseFile.comment && frameworkBuildPhaseFile.comment.indexOf(fileBasename) != -1) { fileId = frameworkBuildPhaseFile.value; pbxFrameworksBuildPhaseObjFiles.splice(i,1); // MUST remove from frameworks build phase or else CodeSignOnCopy won't do anything. break; } } return fileId; } function getFileRefFromName(myProj, fName) { const fileReferences = myProj.hash.project.objects['PBXFileReference']; var fileRef = ''; for(var ref in fileReferences) { if(ref.indexOf('_comment') == -1) { var tmpFileRef = fileReferences[ref]; if(tmpFileRef.name && tmpFileRef.name.indexOf(fName) != -1) { fileRef = ref; break; } } } return fileRef; } const xcodeProjPath = fromDir('platforms/ios','.xcodeproj', false); const projectPath = xcodeProjPath + '/project.pbxproj'; const myProj = xcode.project(projectPath); function addRunpathSearchBuildProperty(proj, build) { const LD_RUNPATH_SEARCH_PATHS = proj.getBuildProperty("LD_RUNPATH_SEARCH_PATHS", build); if(!LD_RUNPATH_SEARCH_PATHS) { proj.addBuildProperty("LD_RUNPATH_SEARCH_PATHS", "\"$(inherited) @executable_path/Frameworks\"", build); } else if(LD_RUNPATH_SEARCH_PATHS.indexOf("@executable_path/Frameworks") == -1) { var newValue = LD_RUNPATH_SEARCH_PATHS.substr(0,LD_RUNPATH_SEARCH_PATHS.length-1); newValue += ' @executable_path/Frameworks\"'; proj.updateBuildProperty("LD_RUNPATH_SEARCH_PATHS", newValue, build); } } myProj.parseSync(); addRunpathSearchBuildProperty(myProj, "Debug"); addRunpathSearchBuildProperty(myProj, "Release"); // unquote (remove trailing ") var projectName = myProj.getFirstTarget().firstTarget.name.substr(1); projectName = projectName.substr(0, projectName.length-1); //Removing the char " at beginning and the end. const groupName = 'Embed Frameworks ' + context.opts.plugin.id; const pluginPathInPlatformIosDir = projectName + '/Plugins/' + context.opts.plugin.id; process.chdir('./platforms/ios'); const frameworkFilesToEmbed = fromDir(pluginPathInPlatformIosDir ,'.framework', false, true); process.chdir('../../'); if(!frameworkFilesToEmbed.length) return; myProj.addBuildPhase(frameworkFilesToEmbed, 'PBXCopyFilesBuildPhase', groupName, myProj.getFirstTarget().uuid, 'frameworks'); for(var frmFileFullPath of frameworkFilesToEmbed) { var justFrameworkFile = path.basename(frmFileFullPath); var fileRef = getFileRefFromName(myProj, justFrameworkFile); var fileId = getFileIdAndRemoveFromFrameworks(myProj, justFrameworkFile); // Adding PBXBuildFile for embedded frameworks var file = { uuid: fileId, basename: justFrameworkFile, settings: { ATTRIBUTES: ["CodeSignOnCopy", "RemoveHeadersOnCopy"] }, fileRef:fileRef, group:groupName }; myProj.addToPbxBuildFileSection(file); // Adding to Frameworks as well (separate PBXBuildFile) var newFrameworkFileEntry = { uuid: myProj.generateUuid(), basename: justFrameworkFile, fileRef:fileRef, group: "Frameworks" }; myProj.addToPbxBuildFileSection(newFrameworkFileEntry); myProj.addToPbxFrameworksBuildPhase(newFrameworkFileEntry); } fs.writeFileSync(projectPath, myProj.writeSync()); console.log('Embedded Frameworks In ' + context.opts.plugin.id); }; 

На самом деле этот крючок:

  1. Создает «фазу сборки», названную после вашего идентификатора плагина, настроенного на «Копировать файлы», причем целью этой копии является «Frameworks».
  2. Находит и добавляет ваши файлы .framework к вышеуказанной фазе сборки, в свою очередь, внедряя ее.
  3. Устанавливает свойство сборки Xcode с именем LD_RUNPATH_SEARCH_PATHS чтобы также искать встроенные фреймворки в "@executable_path/Frameworks" (Это была встроенная структура, которая будет скопирована после «Фазы сборки» -> «Рамки».
  4. Настраивает ключ ATTRIBUTES, устанавливая «CodeSignOnCopy» и «RemoveHeadersOnCopy» для ваших файлов .framework.
  5. Удаляет ваши файлы .framework из FrameworksBuildPhase и повторно добавляет их в FrameworksBuildPhase в качестве новых разделенных PBXBuildFiles (Same PBXFileReference), это должно быть сделано для того, чтобы «CodeSignOnCopy» означал что угодно, не удаляя его, если вы откроете проект с Xcode, вы не найдете галочку на фазе сборки, которая говорит, что она подпишет ее.

Обновлено 1: код крюка, модификации:

  1. Крючок автоматически находит ваши файлы .framework, нет необходимости редактировать крючок.
  2. Добавлена ​​важная модификация, устанавливающая ATTRIBUTES «CodeSignOnCopy» и «RemoveHeadersOnCopy» для ваших файлов .framework.
  3. Улучшен захват, чтобы он мог работать в таком случае, когда несколько плагинов используют этот крючок.

Обновление 2

  1. Поскольку мой запрос на перенос принят, вам больше не нужно устанавливать свою собственную вилку.
  2. Улучшен код крючка.

Обновление 3 (19/09/2016)

Модифицированный сценарий крюка в соответствии с предложением Макс Уэйлера, поскольку я столкнулся с той же проблемой по сравнению с Xcode 8.

Итоговая записка

После того, как вы загрузите приложение в AppStore, если проверка не завершится неудачей из-за неподдерживаемых архитектур (i386 и т. Д.), Попробуйте следующий плагин Cordova (только hook, нет собственного кода): zcordova-plugin-archtrim

Чтобы получить плагин для сборки с проектом на XCode 8.0 и cordova-ios 4.2, мне пришлось запустить hook на этапе after_build . Кроме того, убедитесь, что среда узла использует последнюю версию xcode-node (^ 0.8.9), или вы получите ошибки на фазе файлов копий.

<framework src="lib/myCustom.framework" custom="true" embed="true" /> <hook type="after_build" src="hooks/add_embedded.js" />

Для plugin.xml для «Кордовы» необходимо скопировать файл фреймворка custom="true" , что в конечном итоге противоречило изменениям, внесенным в .pbxproj, когда этот крюк запускался в after_platform add или даже after_prepare.

@Alon Amir, спасибо за обмен, он работает красиво! Хотя мое приложение отлично работает в Debug, но не в режиме Release. Я понял, что LD_RUNPATH_SEARCH_PATHS был добавлен только в режим Debug, поскольку proj.getBuildProperty без параметра build принимает первый результат. Я немного изменил ваш код, чтобы он работал в Debug, а также в режиме Release:

 function addRunpathSearchBuildProperty(proj, build) { const LD_RUNPATH_SEARCH_PATHS = proj.getBuildProperty("LD_RUNPATH_SEARCH_PATHS", build); if(!LD_RUNPATH_SEARCH_PATHS) { proj.addBuildProperty("LD_RUNPATH_SEARCH_PATHS", "\"$(inherited) @executable_path/Frameworks\"", build); } else if(LD_RUNPATH_SEARCH_PATHS.indexOf("@executable_path/Frameworks") == -1) { var newValue = LD_RUNPATH_SEARCH_PATHS.substr(0,LD_RUNPATH_SEARCH_PATHS.length-1); newValue += ' @executable_path/Frameworks\"'; proj.updateBuildProperty("LD_RUNPATH_SEARCH_PATHS", newValue, build); } } myProj.parseSync(); addRunpathSearchBuildProperty(myProj, "Debug"); addRunpathSearchBuildProperty(myProj, "Release"); 

embed="true" поддерживается как cordova-ios 4.4.0, так и cordova 7.0.0, который был выпущен сегодня. https://cordova.apache.org/docs/en/latest/plugin_ref/spec.html#framework https://issues.apache.org/jira/browse/CB-11233

  • Когда необходимо скомпилировать i386 на iOS
  • Как получить штрих-код ISBN в iOS
  • self.navigationController.interactivePopGestureRecognizer.enabled = NO; не работает в iOS 8
  • Тест Swift не смог найти свойство класса Swift для Objective-C VC
  • Правила ресурса подписи кода. Путь не работает на Jenkins, CODE_SIGN_RESOURCE_RULES_PATH
  • Библиотека шрифтов для iOS
  • Совместимость 64 бит iOS
  • UITableView Прокрутка автоматически вверх до начала после начала / окончания обновления вызова для регулировки высоты
  • Ошибка OSStatus -67028 При создании специального приложения iOS
  • Xcode Analyzer vs OCLint в 2016 году
  • Невозможно загрузить модуль «XMPP_Messenger_iOS» как «ошибка xmpp_messenger_ios в Swift
  • Interesting Posts

    Как Fabric получает iOS UDID устройства iOS?

    Каким образом можно быстро переключаться между вкладками в XCode4

    iOS: Облицовочная проблема при обновлении от кордовы 2.2.0 до 2.3.0

    Удерживайте NSOperationQueue до завершения предыдущей операции

    Значок приложения не изменяется на пользовательский значок с помощью cordova

    обрезать увеличенное изображение в ImageView внутри scrollView

    IOS Jailbreak Как перехватывать SMS / текстовые сообщения

    OTA – myApp не может быть установлен в это время – не удалось проверить исполняемый файл

    Конфликт деревьев при обновлении Обновление

    Замена для метода indexOf (_ :) для массива в Swift 3

    Масштабирование UIView в одном направлении с помощью UIPinchGestureRecognizer

    iOS Enterprise Distribution – значок приложения не отображается на плате весов для устройств iOS 9

    Индикатор раскрытия аксессуара не отображается в пользовательской ячейке

    UITextView смещает текст по-другому, чем UILabel

    Откройте страницу страницы с помощью собственного приложения Facebook на iOS

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.