cordova-1.9.0.js 파악하기 (2) - iOS
이번엔 define 및 require 가 사용된 exec 함수에 대해서 알아보자.
define, require 를 간단하게 설명하자면,
define 은 private 속성인 modules 객체에 id 와 function 을 등록하는 과정이며,
require 는 define 된 function 으로 객체를 생성하여 리턴해준다.
define 은 Class 를 작성하는 것이라면, require 는 객체(인스턴스)를 생성하는 것으로 볼 수 있다.
이 exec 를 define 하는 것만으로 99줄이므로 간단하게 살펴보도록 하겠다.
▶ Cordova for iOS - define
// file: lib/ios/exec.js define("cordova/exec", function(require, exports, module) { /** * Creates a gap bridge iframe used to notify the native code about queued * commands. * * @private */ var cordova = require('cordova'), utils = require('cordova/utils'), gapBridge, createGapBridge = function() { gapBridge = document.createElement("iframe"); gapBridge.setAttribute("style", "display:none;"); gapBridge.setAttribute("height","0px"); gapBridge.setAttribute("width","0px"); gapBridge.setAttribute("frameborder","0"); document.documentElement.appendChild(gapBridge); }, channel = require('cordova/channel'); module.exports = function() { if (!channel.onCordovaInfoReady.fired) { utils.alert("ERROR: Attempting to call cordova.exec()" + " before 'deviceready'. Ignoring."); return; } var successCallback, failCallback, service, action, actionArgs, splitCommand; 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 { // FORMAT TWO splitCommand = arguments[0].split("."); action = splitCommand.pop(); service = splitCommand.join("."); actionArgs = Array.prototype.splice.call(arguments, 1); } // Start building the command object. var command = { className: service, methodName: action, "arguments": [] }; // 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}; } if (callbackId !== null) { command["arguments"].push(callbackId); } for (var i = 0; i < actionArgs.length; ++i) { var arg = actionArgs[i]; // nulls are pushed to the args now (becomes NSNull) if (arg === undefined || arg === null) { command["arguments"].push(arg); } else if (typeof(arg) == 'object' && !(utils.isArray(arg))) { command.options = arg; } else { command["arguments"].push(arg); } } // Stringify and queue the command. We stringify to command now to // effectively clone the command arguments in case they are mutated before // the command is executed. cordova.commandQueue.push(JSON.stringify(command)); // If the queue length is 1, then that means it was empty before we queued // the given command, so let the native side know that we have some // commands to execute, unless the queue is currently being flushed, in // which case the command will be picked up without notification. if (cordova.commandQueue.length == 1 && !cordova.commandQueueFlushing) { if (!gapBridge) { createGapBridge(); } gapBridge.src = "gap://ready"; } }; });
Line 1 : 주석을 보면 알 수 있듯이 여러 파일로 쪼개어 작업했던 것을 한 파일로 Merge 했음을 알 수 있다.
Line 2 : define 함수를 사용하여 Class 를 만드는 것으로 첫번째 인수에는 id,
두번째 인수는 function 원형이 들어감을 알 수 있다.
소스를 검색하면 require("cordova/exec") 를 사용하여 인스턴스를 생성할 것이다.
Line 8 : require 로 cordova 인스턴스를 생성한다.
Line 9 : require 로 utils 인스턴스를 생성한다.
Line 12 : iOS Phonegap의 경우 iframe 을 이용하여, Native App 과 WebView 간에 정보 공유를 한다.
이러한 iframe 을 생성하는 함수
Line 19 : require 를 이용하여 channel 인스턴스를 생성한다.
Line 22 : require 로 인스턴스를 생성할 때 리턴되는 module.exports 를 작성한다.
Line 23 : 폰갭이 사용할 준비가 되어 있지 않은 상태에서 접근 할 경우 return
Line 31 : phonegap의 경우 Javascript 에서 successCallback, failCallback, service, action, actionArgs
를 넘기는데, 이러한 인수들을 변수에 저장하는 과정
successCallback : 사용자에 의해 작성된 함수로 exec 성공시 호출된다. ( Script 실행 )
failCallback : 사용자에 의해 작성된 함수로 exec 실패시 호출된다. ( Script 실행 )
service : 폰갭 플러그인 이름 ( Script ↔ Native App )
폰갭 플러그인 중 실행하고자 하는 이름을 입력한다.
action : 폰갭 플러그인 동작을 위한 이름 ( Native App 실행 )
사용자 플러그인의 경우 Native App 에서 action 명으로 어떤 동작을 할지 결정할 수 있다.
actionArgs : service 와 action 이 넘어 올 때 파라메터가 넘어온다. ( Native App ↔ Script)
Line 53 : command 객체 생성. 추후 String 으로 만들기 위한 JSON 객체
service, action 저장
Line 61 : successCallback, failCallback 등록
Line 66 : Callback Id 등록
Line 70 : 넘어온 actionArgs 를 등록
Line 85 : JSON.stringify 를 이용해 command 객체를 String 으로 생성
Line 91 : cordova.commandQueue 이 하나인 경우 gapBridge.src 를 "gap://ready" 기본 String 형으로 저장
위와 같이 define, require 를 사용하는 exec 를 간단하게 살펴보았다.
exec 함수는 사용자 플러그인으로 생성할 경우 Javascript 에서 작성하여, 실행되도록 하는 것으로
WebView의 Javascript 와 Native App 을 연결시켜주는 역할을 담당한다.
define 과 require 를 이용하여, 여러 객체들이 cordova-1.9.0.js 에 포함되어 있는데,
define, require, exec 의 개념을 어느 정도 알고 있다면,
다른 객체들을 해석하는 데는 그리 어렵지 않을 것이다.
지금 이 글을 포스팅 하고 있는 나 조차도 Javascript의 여러 기술들과 Phonegap의 js 에 대해서
자세히 알지는 못한다.
이러한 구조로 구성되어 있고, 개략적인 개념만 파악하고 있는 것으로 만족해야겠다.