Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-24740] iOS - Unable to use Mapbox SDK (third-party framework) with Hyperloop

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionNot Our Bug
Resolution Date2017-08-08T08:25:34.000+0000
Affected Version/sn/a
Fix Version/sn/a
ComponentsHyperloop
LabelsHyperloop, appcelerator, ios, mapbox, thirdparty
ReporterLa Fabrik
AssigneeEric Merriman
Created2017-05-25T21:47:44.000+0000
Updated2017-08-23T18:19:14.000+0000

Description

Hi, I'm trying to use Hyperloop to integrate the mapbox framework to my app, but it is not working. After following the appcelerator's guide for include third-party framework to ios, when I run the app on the ios simulator, the app crashes and I got a crash report (see attachments). step to reproduce : -create a new project in appcelerator using the default alloy project with hyperloop enabled. -download the Mapbox iOS sdk at http://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/mapbox-ios-sdk-3.5.4-dynamic.zip -Unzip and place the Mapbox.framework file in "src" folder in the project's root directory -I add an appc.js file on the project's root directory with those lines :
module.exports = {
	hyperloop: {
		ios: {
			xcodebuild: {
				flags: {
					FRAMEWORK_SEARCH_PATHS: '../../src',
                                        LD_RUNPATH_SEARCH_PATHS: '@executable_path'
				},
				frameworks: [
					'Mapbox'
				]
			},
			thirdparty: {
				'Mapbox': {
					source: ['src'],
					header: 'src',
					resource: 'src'
				}
			}
		}
	}
};

-Add the "MGLMapboxAccessToken" key in the tiapp.xml -Edit the index.js controler :
function doClick(e) {
	alert($.label.text);
}
var MGLMapView = require('Mapbox/MGLMapView');
var map = new MGLMapView();
$.index.add(map);
$.index.open();
-run the app on iOS simulator

Attachments

FileDateSize
mapboxtest_2017-05-26-084428_Julien.crash2017-05-25T21:45:56.000+000016203

Comments

  1. La Fabrik 2017-06-14

    Hello @emerriman , Have you got some news? Thanks,
  2. Dee Clawson 2017-07-02

    Just a general note for who ever is working on this. This problem is because Hyperloop doesn't support embedded binaries. I was able to get Mapbox to work using some modification to ti.dynamiclib....
  3. La Fabrik 2017-07-03

    Hello @Dee Clawson Thanks for the reply, I already tried this solution but without success, can you post an example please?
  4. Dee Clawson 2017-07-03

    Hey La Fabrik, Sorry no, our code contains some trade secrets. When ti.dynamiclib is properly modified it works perfect though, best of luck. I would suggest getting Matise's module to work first. https://github.com/MatiseAms/ti-mapbox-gl Once you understand it and how he set up dynamiclib it is pretty easy to get working.
  5. Dee Clawson 2017-07-03

    Actually here you go:
       module.exports = {
       	hyperloop: {
       		ios: {		
       			xcodebuild: {
       				flags: {
       					FRAMEWORK_SEARCH_PATHS: '../../src',
       					LD_RUNPATH_SEARCH_PATHS: '$(inherited) "@executable_path/Frameworks" $(FRAMEWORK_SEARCH_PATHS)'
       				}
       			},
       			thirdparty: {
       				'Mapbox': {
       					source: ['src'],
       					header: 'src',
       					resource: 'src'
       				}
       			}
       		}
       	}
       };
       
       if (!Array.prototype.last) {
         Object.defineProperty(Array.prototype, 'last', {
           value: function() {
             return this[this.length - 1];
           }
         });
       }
       
       exports.id = 'ti.dynamiclib';
       exports.cliVersion = '>=3.2';
       exports.init = function (logger, config, cli, appc) {
       	cli.on('build.ios.xcodeproject', {
       		pre: function (data) {
       			
       			// Replace the following variables with your framework / script:
       			// ---
       			var scriptPath = null; '../../src/Mapbox.framework/strip-frameworks.sh'; //'<path-to-strip-frameworks-script>/strip-frameworks.sh'; // Or set to null if not required
       			var frameworkPaths = [
       				'../../src/Mapbox.framework'
       			];
       			// ---
       			
       			var builder = this;
       			var xcodeProject = data.args[0];
       			var xobjs = xcodeProject.hash.project.objects;
       
       			if (typeof builder.generateXcodeUuid !== 'function') {
       				var uuidIndex = 1;
       				var uuidRegExp = /^(0{18}\d{6})$/;
       				var lpad = appc.string.lpad;
       
       				Object.keys(xobjs).forEach(function (section) {
       					Object.keys(xobjs[section]).forEach(function (uuid) {
       						var m = uuid.match(uuidRegExp);
       						var n = m && parseInt(m[1]);
       						if (n && n > uuidIndex) {
       							uuidIndex = n + 1;
       						}
       					});
       				});
       
       				builder.generateXcodeUuid = function generateXcodeUuid() {
       					return lpad(uuidIndex++, 24, '0');
       				};
       			}
       			addLibrary(builder, cli, xobjs, frameworkPaths);
       			addScriptBuildPhase(scriptPath);
       		}
       	});
       };
       
       function addLibrary(builder, cli, xobjs, frameworkPaths) {
       	if (!frameworkPaths || frameworkPaths.length == 0) {
       	    return; // Skip if no frameworks are specified
       	}
       	
       	frameworkPaths.forEach(function (framework_path) {
       		var framework_name = framework_path.split('/').last();
       
       		// B6CE2C7E1C90C08400B37C55
       		var frameword_uuid = builder.generateXcodeUuid();
       
       		// B6CE2C7F1C90C08400B37C55
       		var embeddedFrameword_uuid = builder.generateXcodeUuid();
       
       		// B6CE2C7D1C90C08400B37C55
       		var fileRef_uuid = builder.generateXcodeUuid();
       
       		// B6CE2C801C90C08400B37C55
       		var embeddedFrameword_copy_uuid = builder.generateXcodeUuid();
       
       		createPBXBuildFile(xobjs, frameword_uuid, fileRef_uuid, embeddedFrameword_uuid, framework_name);
       		createPBXCopyFilesBuildPhase(xobjs, embeddedFrameword_copy_uuid, embeddedFrameword_uuid, framework_name);
       		createPBXFileReference(xobjs, fileRef_uuid, framework_path, framework_name);
       		createPBXFrameworksBuildPhase(xobjs, frameword_uuid, framework_name);
       		createPBXGroup(xobjs, fileRef_uuid, framework_name);
       		createPBXNativeTarget(xobjs, embeddedFrameword_copy_uuid);
       	});
       }
       
       function addScriptBuildPhase(scriptPath) {
       	if (!scriptPath) return;
       	
       	var script_uuid = builder.generateXcodeUuid();
       	var shell_path = '/bin/sh';
       	var shell_script = 'bash \"' + scriptPath + '\"';
       
       	createPBXRunShellScriptBuildPhase(xobjs, script_uuid, shell_path, shell_script);
       	createPBXRunScriptNativeTarget(xobjs, script_uuid);
       }
       
       function createPBXBuildFile(xobjs, frameword_uuid, fileRef_uuid, embeddedFrameword_uuid, framework_name) {
       
       	/**
       	 *	// <YourFramework>.framework in Frameworks
       	 *	B6CE2C7E1C90C08400B37C55 = {
       	 *		isa = PBXBuildFile;
       	 *		// <YourFramework>.framework
       	 *		fileRef = B6CE2C7D1C90C08400B37C55
       	 *	};
       	 */
       	xobjs.PBXBuildFile[frameword_uuid] = {
       		isa: 'PBXBuildFile',
       		fileRef: fileRef_uuid,
       		fileRef_comment: framework_name + ' in Frameworks'
       	};
       	xobjs.PBXBuildFile[frameword_uuid][frameword_uuid + '_comment'] = framework_name + ' in Frameworks';
       
       	/**
       	 *	// <YourFramework>.framework in Embed Frameworks
       	 *	B6CE2C7F1C90C08400B37C55 = {
       	 *		isa = PBXBuildFile;
       	 *		// <YourFramework>.framework
       	 *		fileRef = B6CE2C7D1C90C08400B37C55
       	 *		settings = {
       	 *			ATTRIBUTES = [CodeSignOnCopy, RemoveHeadersOnCopy]
       	 *		}
       	 *	}
       	 */
       	xobjs.PBXBuildFile[embeddedFrameword_uuid] = {
       		isa: 'PBXBuildFile',
       		fileRef: fileRef_uuid,
       		fileRef_comment: framework_name + ' in Embed Frameworks',
       		settings: {
       			ATTRIBUTES: ['CodeSignOnCopy', 'RemoveHeadersOnCopy']
       		}
       	};
       	xobjs.PBXBuildFile[embeddedFrameword_uuid][embeddedFrameword_uuid + '_comment'] = 'MyFramework in Embed Frameworks';
       
       }
       
       function createPBXCopyFilesBuildPhase(xobjs, embeddedFrameword_copy_uuid, embeddedFrameword_uuid, framework_name) {
       
       	/**
       	 *	B6CE2C801C90C08400B37C55 = {
       	 *		isa = PBXCopyFilesBuildPhase;
       	 *		buildActionMask = 2147483647;
       	 *		dstPath = "";
       	 *		dstSubfolderSpec = 10;
       	 *		files = (
       	 *			// <YourFramework>.framework in Embed Frameworks
       	 *			B6CE2C7F1C90C08400B37C55,
       	 *		);
       	 *		name = "Embed Frameworks";
       	 *		runOnlyForDeploymentPostprocessing = 0;
       	 *	};
       	 */
       	xobjs.PBXCopyFilesBuildPhase = xobjs.PBXCopyFilesBuildPhase || {};
       	xobjs.PBXCopyFilesBuildPhase[embeddedFrameword_copy_uuid] = {
       		isa: 'PBXCopyFilesBuildPhase',
       		buildActionMask: '2147483647',
       		dstPath: '""',
       		dstSubfolderSpec: '10',
       		files: [{
       			value: embeddedFrameword_uuid + '',
       			comment: framework_name + ' in Embed Frameworks'
       		}],
       		name: '"Embed Frameworks"',
       		runOnlyForDeploymentPostprocessing: 0
       	};
       }
       
       function createPBXFileReference(xobjs, fileRef_uuid, framework_path, framework_name) {
       	/**
       	 *	B6CE2C7D1C90C08400B37C55 = {
       	 *		isa = PBXFileReference;
       	 *		lastKnownFileType = wrapper.framework;
       	 *		name = <YourFramework>.framework;
       	 *		path = ../../modules/iphone/com.janx.wowza/1/platform/<YourFramework>.framework;
       	 *		sourceTree = "<group>";
       	 *	};
       	 */
       	xobjs.PBXFileReference[fileRef_uuid] = {
       		isa: 'PBXFileReference',
       		lastKnownFileType: 'wrapper.framework',
       		name: framework_name,
       		path: framework_path,
       		sourceTree: '"<group>"'
       	};
       }
       
       function createPBXFrameworksBuildPhase(xobjs, frameword_uuid, framework_name) {
       	/**
       	 *	1D60588F0D05DD3D006BFB54 = {
       	 *		isa = PBXFrameworksBuildPhase;
       	 *		buildActionMask = 2147483647;
       	 *		files = (
       	 *			// MyFramework in Frameworks
       	 *			B6CE2C7E1C90C08400B37C55,
       	 *			more stuff
       	 *		);
       	 *	};
       	 */
       	for (var key in xobjs.PBXFrameworksBuildPhase) {
       		xobjs.PBXFrameworksBuildPhase[key].files.push({
       			value: frameword_uuid + '',
       			comment: framework_name + ' in Frameworks'
       		});
       		return;
       	}
       }
       
       function createPBXGroup(xobjs, fileRef_uuid, framework_name) {
       	for (var key in xobjs.PBXGroup) {
       		if (xobjs.PBXGroup[key].name == 'Frameworks') {
       			xobjs.PBXGroup[key].children.push({
       				value: fileRef_uuid,
       				comment: framework_name
       			});
       			return;
       		}
       	}
       }
       
       function createPBXNativeTarget(xobjs, embeddedFrameword_copy_uuid) {
       	for (var key in xobjs.PBXNativeTarget) {
       		xobjs.PBXNativeTarget[key].buildPhases.push({
       			value: embeddedFrameword_copy_uuid + '',
       			comment: 'Embed Frameworks'
       		});
       		return;
       	}
       }
       
       function createPBXRunShellScriptBuildPhase(xobjs, script_uuid, shell_path, shell_script){
       	xobjs.PBXShellScriptBuildPhase = xobjs.PBXShellScriptBuildPhase || {};
       	xobjs.PBXShellScriptBuildPhase[script_uuid] = { 
        		isa: 'PBXShellScriptBuildPhase', 
        		buildActionMask: '2147483647', 
        		files: '(\n)', 
        		inputPaths: '(\n)', 
        		outputPaths: '(\n)', 
        		runOnlyForDeploymentPostprocessing: 0, 
        		shellPath: shell_path, 
        		shellScript: JSON.stringify(shell_script) 
        	};
       }
       
       function createPBXRunScriptNativeTarget(xobjs, script_uuid) {
       	for (var key in xobjs.PBXNativeTarget) {
       		xobjs.PBXNativeTarget[key].buildPhases.push({ 
               		value: script_uuid + '', 
               		comment: 'Run Script Phase'
             		});
       		return;
       	}
       }
       
  6. Dee Clawson 2017-07-05

    Hey La Fabrik, I did you one better. I have made an example iOS project with it working. https://github.com/kdclaw3/hyperloop-mapbox
  7. La Fabrik 2017-07-06

    hi @Dee Clawson, Oh thank you, I'll try it asap!
  8. Hans Knöchel 2017-08-08

    Resolving issue since this was no Titanium related issue. Side-note: Hyperloop 2.2.0 and SDK 6.2.0 will have core-support for dynamic libraries, so hook won't be necessary anymore.
  9. Lee Morris 2017-08-23

    Closing ticket with regards to the above observations.

JSON Source