타이타늄 빌드 오류에 대처하는 우리들의 자세

타이타늄 1.8 에서 종종 코드는 이상이 없는데, 빌드하고 나면 화면에 반영이 되지 않고 캐시되는 오류가 종종 있었다.

이런경우엔 보통 build 폴더를 날리고 재빌드하면 정상적으로 동작하는 경우가 있었는데, 2.0 이후 부터는 정상적으로 잘 동작하던 프로젝트를 clean만 해도 아래와 같은 빌드 오류를 내뱉는다.

[INFO] Performing clean build

[ERROR]

[ERROR] Error: Traceback (most recent call last):

File “/Library/Application Support/Titanium/mobilesdk/osx/2.0.2.GA/iphone/builder.py”, line 1318, in main

execute_xcode(“iphonesimulator%s” % link_version,[“GCC_PREPROCESSOR_DEFINITIONS=__LOG__ID__=%s DEPLOYTYPE=development TI_DEVELOPMENT=1 DEBUG=1 TI_VERSION=%s %s %s” % (log_id,sdk_version,debugstr,kroll_coverage)],False)

File “/Library/Application Support/Titanium/mobilesdk/osx/2.0.2.GA/iphone/builder.py”, line 1224, in execute_xcode

output = run.run(args,False,False,o)

File “/Library/Application Support/Titanium/mobilesdk/osx/2.0.2.GA/iphone/run.py”, line 41, in run

sys.exit(rc)

SystemExit: 65

타이타늄 커뮤니티를 뒤져보면 위와 비슷한 오류로 고생하는 개발자가 엄청 많다. 나 또한 이문제로 몇날 몇시간을 허비한지 모르겠다… -_-;; 정확한 원인은 나도 모른다.  타이타늄 코어 개발자는 알겠지..

여튼 내가 확인한 가장 확실한 해결책은 다음과 같다.

1) 일반 리소스 폴더를 안전한 곳에 백업해둔다.

2) 그리고 타이타늄 스튜디오에서 해당 프로젝트를 제거한다. 제거 할때 프로젝트 폴더 전체를 지우자!

3) 다시 새로운 프로젝트를 생성한다.

4) 여기가 가장  중요하다, 생성한 프로젝트를 바로 빌드한다.

5) 오류없이 빌드가 되서 시뮬레이터가 뜬다면 잘 된거다.

6) 이제 원본 소스를 프로젝트에 복사하고, 다시 빌드해보자!

 

[summary]

1) First, backup Resource fold of  your project

2) Remove  the project in Titanium Studio (make sure delete project contents on disk)

3) Create new Mobile Project as a sample.

4) Important!! You must build the Sample Project  immediately.

5) Confirm the Sample Project has build without an error.

6) Now, copy origin resources to the Project  and Rebuild!

7) OR, Make sure your image resource name is written by English!

———-

[Update 2012-6-14]

자꾸 빌드가 안되는 오류의 원인을 찾았다.  원인은 바로 이미지 리소스들의 이름이 한글로 되어 있어서 문제였다. 커뮤니티에서도 이런 문제가 발생했을대 이미지 이름을 영어로 바꿔라 라는 얘기가 있었는데,.. 아 이게 이문제일 쭐이야..

한글로 된 이미지 이름이 없는 줄 알았는데,.. 파일이 딱 하나 존재했다.  그리고 이름을 변경해 빌드하니 제대로 된다.

아~ 나 그동안 뭐한거니? ㅇㅎㅎ

앱이름을 한글로 쓰기

타이타늄 모바일 앱의 기본 언어셋은 영어다.

이 말은 즉 특별한 한글 이름을 지정하지 않으면 영문으로 앱이름을 써야한다는 얘기도 되겠다.

그렇다면, 앱 이름은 어디서 설정하는 걸까?

먼저 tiapp.xml 파일을 뒤져보자.

<?xml version=”1.0″ encoding=”UTF-8″?>

<ti:app xmlns:ti=”http://ti.appcelerator.org”>

<sdk-version>2.0.1.GA2</sdk-version>

<id>com.miconblog.sampleapp</id>

<name>SampleApp</name>

<version>1.0</version>

…. 이하 생략

대충 살펴보니 <name> 태그가 보인다

. 그리고 이 태그에 값을 설정하면 실제 빌드되어 만들어지는 앱의 이름으로 쓰인다는 사실도 쉽게 알수있다.

그럼 이 태그에 한글을 넣으면 될까? 아마 빌드해보면 아래와 같이 에러가 날것이다.

UnicodeDecodeError: ‘utf8’ codec can’t decode byte 0xb5 in position 0: invalid start byte

그럼 도대체 어디에…???

국제화와 지역화 그리고 세계화

타이타늄 프로젝트 폴더를 보면, i18n이라는 폴더가 있다. 이 폴더가 없는 경우엔 Resouces 폴더와 동등 위치(최상위)에 만들어주면 된다. 여튼 이 폴더는 국제화(internationalization)라는 단어를 줄여서 첫글자와 마지막 글자 그리고 그 사이의 글자가 18개를 의미하는 단어다. 즉, i18n 이라는 얘기는 국제화를 의미하고, 영어권에서는 통용되는 줄임말이다.

그럼 여기서 잠깐,  l

10n은 뭘까? 이쯤되면 대충 지역화(localization)라는걸 유추해볼수있다. 그리고 g11n은 세계화(globalization)라는 것쯤은 일단 상식으로 알아두자!

다시 돌아와서, 바로 이 i18n 폴더에 국제화와 관련된 언어셋들을 정리해두면, 타이타늄이 알아서 상황에 맞게 표시해준다.

그럼 만들어보자!

한글 언어 설정

  1. 먼저 i18n 폴더를 최상위에 만든다.
  2. 그리고 그 하위에 ko 폴더를 만든다.
  3. 그리고 그 안에 app.xml 파일을 만들자.

app.xml 파일은 아래와 같이 작성한다.

<?xml version=”1.0″ encoding=”UTF-8″?>

<resources>

<string name=”appname”>한글이름</string>

</resources>

—-

[summary]

if you want i18n

1. make i18n folder

2. make sub folder for language (ex. ko, en, etc…)

3. create app.xml file

4. write your properties

멀티 스레드로 윈도우 열기

웹브라우저에서 동작하는 자바스크립트는 싱글 스레드로 동작한다. 
즉,  어떤 코드를 실행하던간에 순차적으로 실행되고, 이 순서에 따라 의존성도 생긴다.

하지만 타이타늄 모바일의 경우 두가지 방법으로 윈도우를 열수있다.

1. 싱글 스레드로 윈도우 열기 

[app.js]

var parentWin = Ti.UI.createWindow();
var button = Ti.UI.createButton();
button.addEventListener(“click”, function(e){
var childWin = Ti.UI.createWindow();
childWin.open();
});
parentWin.add(button);
parentWin.open();

위와 같이 같은 파일 안에서 윈도우를 정의할 경우 같은 스레드에서 윈도우가 열린다.

2. 멀티 스레드로 윈도우 열기 

멀티 스레드로 윈도우를 열려면, 다음과 같이 윈도우 생성시 URL 속성을 지정한다.

[app.js]

var parentWin = Ti.UI.createWindow();
var button = Ti.UI.createButton();
button.addEventListener(“click”, function(e){
var childWin = Ti.UI.createWindow({ url: “./childWindow.js” });
childWin.open();

Ti.App.fireEvent(“fooEvent”, {data:”message”});
});
parentWin.add(button);
parentWin.open();

[childWindow.js]

var win = Ti.UI.currentWindow;

Ti.App.addEventListener(“fooEvent”, function(e){
Ti.API.info(e.data + ” got it!”);
});

위와 같이 url로 지정하면 childWindow.js 파일 안에 정의된 내용은 다른 스레드로 동작한다.
따라서, 두 윈도우 사이에 데이터를 전송하려면 약간의 시차가 생길수 있다.

예를 들어, 자식 윈도우를 열고
1. childWindow.open()

바로 윈도우로 메시지를 날리면,
2.  Ti.App.fireEvent(“fooEvent”, {data:”message”});

자식 윈도우에서 메시지를 받아야하는데 받지 못한다.
3.  Ti.App.addEventListener(“fooEvent”, function(e){  Ti.API.info(e.data + ” got it!”);  });

따라서 URL을 이용해 윈도우를 열 경우엔, 스레드 생성시간만큼의 약간의 딜레이를 주어야한다.

var childWin = Ti.UI.createWindow({ url: “./childWindow.js” });

childWin.open();
setTimeout(function(){

      Ti.App.fireEvent(“fooEvent”, {data:”message”});

   }, 100); 

});