반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

코로나 네트워킹 과 웹 서비스 2

2011. 10. 24. 21:17 | Posted by 솔웅


반응형
Asynchronous HTTP (비동기 HTTP)

이 기능은 HTTP 메소드 (GET,POST 등)를 사용하거나 개발자가 header와 body를 사용해서 비동기식 HTTP와 HTTPS/SSL 콜을 만들도록 합니다.
코로나는 이 때 서버로부터 어떤 응답을 받는 동안 멈출 필요가 없도록 하는 기능을 제공합니다.
여러분은 네트워크를 통해서 파일을 다운로드 할 수 있습니다. 이 파일을 메모리에 로딩 할 필요가 없습니다. 이것은 해당 파일이나 이미지가 아주 큰 경우에 아주 유용합니다.
코로나는 이와 관련 두개의 샘플 프로젝트를 제공합니다.

AsynchHTTP

local myText = display.newText("(Waiting for response)", 0, 0, native.systemFont, 16)
myText.x = display.contentCenterX
myText.y = 120

local function networkListener( event )
    if ( event.isError ) then
        myText.text = "Network error!"
    else
        myText.text = "See Corona Terminal for response"
        print ( "RESPONSE: " .. event.response )
    end
end

-- Access Google over SSL:
network.request( "https://encrypted.google.com", "GET", networkListener )

편의를 위해 주석부분은 제거했습니다.
간단히 살펴보면 첫 세줄은 텍스트를 뿌려주는 겁니다.
networkListener 함수를 보면 event를 받아서 에러일 경우 에러메세지를 뿌려주고 에러가 아닐 경우는 그 결과값을 터미널에 뿌려줍니다.
결과값은 맨 마지막 줄 network.request를 통해서 받아온 겁니다.


뭐 request 하는 것도 없고 그냥 network.request() 에서 get 방식으로 가져오는 것 밖에는 없네요.

두 번째 예제도 보면요.

AsynchImageDownload

local function networkListener( event )
    if ( event.isError ) then
        print ( "Network error - download failed" )
    else
        myImage = display.newImage( "helloCopy.png", system.TemporaryDirectory, 60, 40 )
        myImage.alpha = 0
        transition.to( myImage, { alpha = 1.0 } )
    end
   
    print ( "RESPONSE: " .. event.response )
end

network.download(
    "http://developer.anscamobile.com/demo/hello.png",
    "GET",
    networkListener,
    "helloCopy.png",
    system.TemporaryDirectory )

-- NOTE: files saved to system.TemporaryDirectory are not guaranteed to persist across launches.
-- Use system.DocumentsDirectory if you want files to persist.

----------------------------------------------------------------------------------------------------
-- Method 2: use display.loadRemoteImage() to get the file and create a display object in one step

local function networkListener2( event )
    if ( event.isError ) then
        print ( "Network error - download failed" )
    else
        event.target.alpha = 0
        transition.to( event.target, { alpha = 1.0 } )
    end
   
    print ( "RESPONSE: " .. event.response )
end

myImage2 = display.loadRemoteImage(
    "http://developer.anscamobile.com/demo/hello.png",
    "GET",
    networkListener2,
    "helloCopy2.png",
    system.TemporaryDirectory,
    60, 280 )


이 샘플은 HTTP로 이미지를 download할 수 있도록 한 건데요.
network.download()부터 보시면 경로가 있고 GET방식으로 불러오고 파일 이름이 있고 이 파일을 system.TemporaryDirectory 에 저장하네요.
중간에 보면 networkListener함수를 불러오는데요.
이 함수는 event를 파라미터로 받습니다.

함수 안을 보면 에러일 경우 에러 메세지 뿌려주고 에러가 아닐경우는 system.TemporaryDirectory에 있는 이미지를 뿌려줍니다.

두 번째 myImage2 변수선언 부분을 보면요.
display.loadRemoteImage()함수를 썼는데 이것도 그 안의 내용은 network.download()와 똑 같습니다.
불러오는 함수가 networkListener2를 불러오고 맨 마지막에 60,280 이란 숫자가 있는게 다르네요.
networkListener2 함수를 살펴보면 마찬가지로 에러일 경우 에러메세지 뿌려주고 에러가 아닐경우는 event.target.alpha =0으로 투명하게 하고 이것을 transition.to함수로 투명도를 없앴습니다.

대충 보니까 network.download()는 다운로드만 받는거고 display.loadRemoteImage() 는 다운로드 받은 다음에 이것을 화면에 뿌려주기까지 하는 거네요.

먼저 공부도 하기 전에 샘플코드를 분석했는데요. 제대로 공부를 함 해 보겠습니다.

Network Requests

network.request( url, method, listener [, params] )
여기서 디폴트 method 는 GET 입니다.
결과 event는 아래와 같은 프로퍼티들을 가집니다.
    •    event.response -- 서버로부트 받은 결과 값 (String)
    •    event.isError -- 네트워크 에러와 관련한 True, False 값
이 두 파라미터는 첫 번째 예제에서 사용했었죠?

예제에는 없지만 여기에 헤더나 바디를 추가할 수 있습니다.
params.headers - 테이블로 선언 함
params.body - 스트링을 담은 HTTP 바디

headers = {}
 
headers["Content-Type"] = "application/json"
headers["Accept-Language"] = "en-US"
 
headers.body = "This is an example request body."

위 샘플을 보면 헤더에는 json 사용한다는 것과 언어는 미국식 영어를 사용한다는게 있고요. body에는 예제 바디라는 문장이 있습니다.
HTML 많이 사용해 보신 분들은 이게 뭔지 다 아시겠죠?

Network Downloads

위의 Network Requests와 거의 유사하구요 + 다운로드 기능까지 있는 겁니다.
메모리에 캐싱하지 않고 제공된 디렉토리에 제공된 이름의 파일을 HTTP로 다운로드 하는 겁니다. 큰 파일일 경우 유용하게 사용 하실 수 있습니다.

network.download( url, method, listener [, params], destFilename [, baseDir] )

디폴트 method는 GET입니다. baseDir는 system.DocumentsDirectory나 system.TemporaryDirectory가 될 수 있습니다.

결과 event로는 Network Requests와 같이 event.response와 event.isError가 있습니다.

예제는 위의 두 번째 예제를 봐 주세요.

Displaying Remote Images

이건 예제에서도 봤듯이 다운로드 하면서 곧바로 화면에 이미지를 출력해 주는 기능입니다.

display.loadRemoteImage( url, method, listener [, params], destFilename [, baseDir] [, x, y] )

다 똑 같구요. 마지막에 이미지의 x,y 값이 있는게 다릅니다.

이 함수에는 세가지 프로퍼티가 있습니다. event.response와 event.isError는 위에것들이랑 똑 같구요. 이 외에 event.target이 있습니다.
이 프로퍼티는 이미지가 다운로드 된 후의 새로 만들어진 display object입니다.

예제는 위 두 번째 예제파일 두 번째 부분을 봐 주세요.

오늘 살펴 본 것은 비동기식 HTTP 통신입니다.

이외에 코로나 DOC에 있는 내용은 OpenFeint, Credit, In-App Purchase 입니다.
Open Feint가 무엇인지 아시려면 아래 링크를 보시면 도움이 될 거예요 .
http://novathin.kr/146
그리고 일반 안드로이드 앱 프로그래밍에서 활용하려면 아래 링크를 참조하시구요.
http://blog.daum.net/gkrttod/1091
코로나에서 이 Open Feint를 사용하는 방법은 제가 공부하고 테스트 하고 난 다음에 올리겠습니다.

Credit은 코로나SDK를 만든 회사인 Ansca Mobile에서 제공하는 서비스 인 것 같습니다.
원격으로 User의 Point를 적립하고 이것을 나중에 in-App Purchase 등 현금 구매 할 때 사용할 수 있도록 하는 서비스 같은데요.
저도 이 부분은 공부를 좀 해 봐야겠어요.

개인적으로 In-App Purchase 에 관심이 있어서요.
나머지 네트워킹 주제들 중에 이 In-App Purchase를 먼저 공부하고 글을 올릴 예정입니다.

그럼...



반응형

코로나 네트워킹 과 웹 서비스 1

2011. 10. 21. 23:27 | Posted by 솔웅


반응형
Networking and Web Services

코로나는 웹 서비스를 위해서 LuaSocket library 2.02버전을 사용합니다.
이 루아 소켓 라이브러리는 SMTP, HTTP, FTP같은 프로토콜을 지원합니다. 이 외에 인코딩 프로토콜인 MIME와 URL 사용 그리고 LTN12 (데이터 트랜스퍼와 필터링) 기능도 지원합니다.
이 Luasocket은 코로나 앱에 이미 인스톨 되 있어서 director.lua나 ui.lua 같이 따로 파일을 복사해 넣을 필요는 없습니다. 하지만 앱실행시의 퍼포먼스 문제로 자동으로 로드되지는 않습니다.
그러므로 이것을 사용하기 위해서는 우선 require 해야 합니다.
local socket=require("socket") 이나 local http = require("http") 같이 먼저 선언하고 난 다음에 사용할 수 있습니다.
LuaSocket 문서는 아래 링크에서 볼 수 있습니다.

http://www.tecgraf.puc-rio.br/~diego/professional/luasocket/reference.html

아래 샘플 코드가 있습니다.
-- Load the relevant LuaSocket modules
local http = require("socket.http")
local ltn12 = require("ltn12")
 
-- Create local file for saving data
local path = system.pathForFile( "hello.png", system.DocumentsDirectory )
myFile = io.open( path, "w+b" )
 
-- Request remote file and save data to local file
http.request{
    url = "http://developer.anscamobile.com/demo/hello.png",
    sink = ltn12.sink.file(myFile),
}
 
-- Display local file
testImage = display.newImage("hello.png",system.DocumentsDirectory,60,50);

print("hello.png image is in " .. path)


일단 http 통신을 하기 위해서 socket.http를 require하고 파일을 transfer하기 위해서 ltn12를 require했습니다.
그 다음 http.request{} 부분을 보면 이미지가 있는 url을 지정하고 이 파일을 미리 지정해 두었던 myFile에 hello.png라는 이름으로 저장합니다.
io.open 으로 미리 쓰기 가능 상태로 두었습니다.
이 path는 device의 기본 폴더입니다. 캡쳐 화면의 터미널 부분을 보면 애플 컴퓨터의 디렉토리가 나오는데요. 아이폰으로 하면 아이폰 폴더 경로가 나올 겁니다.

여기 까지 하면 원격에 있는 이미지를 내 핸드폰으로 가져오는 것까지 성공 한 겁니다.
일단 가져왔으니까 그 다음엔 그냥 보여주면 되겠죠?
display.newImage() 를 통해서 이미지를 폰에 뿌려줍니다.

안드로이드에서는 인터넷을 하려며 퍼미션 (Permissions)를 주어야 합니다.
이 퍼미션은 build.settings 파일에서 설정해 줍니다.

-- build.settings
settings =
{
    androidPermissions =
    {
         "android.permission.INTERNET",
    },
}

광고 ( Ads)
광고는 이전에도 잠깐 다룬적이 있습니다.
현재 코로나는 inMobi 광고만 공식적으로 지원하고 있습니다.
그리고 광고는 시뮬레이터에서 지원을 안하기 때문에 빌드하고 디바이스에 인스톨 한 다음에 테스트 하셔야 됩니다.

아래 샘플 코드를 보시면요.

local ads = require "ads"
 
-- Example for inmobi:
ads.init( "inmobi", "12345abc6789defghijk123" )
 
-- iPhone, iPod touch, iPad
ads.show( "banner320x48", { x=0, y=100, interval=5, testMode=false } )
ads.show( "banner300x250", { x=0, y=100, interval=5, testMode=false } )
 
-- The following are iPad only
ads.show( "banner728x90", { x=0, y=100, interval=5, testMode=false } )
ads.show( "banner468x60", { x=0, y=100, interval=5, testMode=false } )
ads.show( "banner120x600", { x=0, y=100, interval=5, testMode=false } )

처음에 ads를 require합니다.
그리고 ads.init을 불러와서 광고서비스 이름과, App ID 를 세팅하고
ads.show로 적당한 위치에 제공되어지는 배너 크기를 정해 넣습니다.
광고를 보이지 않게 하기 위해선 ads.hide()를 사용합니다.

이 때 테스트를 하시려면요.
App ID 에 4028cb962895efc50128fc99d4b7025b 를 넣으시구요.
testMode=true 로 하세요.

그리고 직접 등록해서 사용하시려면 www.inmobi.com 으로 가셔서 등록하신 후 사용하시구요.

아래는 제 안드로이드 앱인 Spin the bottle 1 Lite 를 코로나로 iPhone 버전으로 만든겁니다.

이 화면은 ads.show() 를 이용해서 banner320x48 를 맨 위에 위치 시킨 겁니다.

이 화면은 ads.show()를 이용해서 banner320x48 를 맨 아래에 위치 시킨 겁니다.

이 화면은 ads.show()를 이용해서 banner300x250 를 적당한 위치에 놓은 겁니다.

지금 아직 앱스토어에서 Waiting for Review 상태라서 앱 URL을 inMobi 에 등록 시키지 못했습니다.
아마 앱이 앱스토어에 오픈 되고 이 URL이 확인 된 다음에 광고를 보내 주나 봅니다.

저희 회사에서 테스트할 수 있는 디바이스가 iPod Touch뿐이라서요. 다른건 테스트를 못 해봤습니다. (테스트 디바이스 지원이 너무 열악해요. 우리 회사... ;;)

iPod Touch 에서는 화면이 뜬 다음에 아직 광고가 나오지 않은 상태에서 다른 화면으로 넘어가면 에러가 나오면서 앱이 강제종료 되더라구요.

이에 iPod Touch에서만 나오는 에러인지 아니면 이런 에러를 방지하는 코딩이 따로 있어야 되는건지는 잘 모르겠어요.

다른 디바이스에서도 테스트를 해 봐야 겠는데....

하옇든 아래 코로나에서 제공하는 Ads관련 샘플 코드를 분석 해 보겠습니다.
혹시 이에 대한 해결책이 있는지 한번 볼까요?

--==================================================================================================
--
-- Abstract: InMobi Ads Sample Project
--
-- This project demonstrates Corona Banner Ads support (from inmobi network).
--
-- IMPORTANT: You must get your own "app ID" from the advertising
-- agency you want to display banner ads for. Further, you must build for device
-- to properly test this sample, because "ads" library is not supported by the
-- Corona Simulator.
--
--   1. Get your app ID (example, from inmobi)
--   2. Modify the code below to use your own app ID
--   3. Build and deploy on device
--
-- The code below demonstrates the different banner ads you can use
-- with the InMobi ad network.
-- Version: 1.0 (July 7, 2011)
-- Version: 1.1 (July 22, 2011) - Added Hide button and changed Next button behavior.
--
-- Sample code is MIT licensed, see http://developer.anscamobile.com/code/license
-- Copyright (C) 2011 ANSCA Inc. All Rights Reserved.
--
--==================================================================================================


--==================================================================================================
-- INITIAL SETTINGS
----------------------------------------------------------------------------------------------------

-- hide the status bar:
display.setStatusBar( display.HiddenStatusBar )

-- Below is the ad network that will be used:

local adNetwork = "inmobi"

-- Replace nil below with your app ID:
-- String; e.g. surrounded by quotes (ex. "abcdefghijklmnop")

local appID = "4028cb962895efc50128fc99d4b7025b"

--==================================================================================================

-- Make Banner Ads features available under "ads" namespace
local ads = require "ads"

-- initialize ad network:
if appID then
    ads.init( adNetwork, appID )
end

-- initial variables
local sysModel = system.getInfo("model")
local sysEnv = system.getInfo("environment")

local bgW, bgH = 320, 480
local currentAdIndex = 1

local adsTable = {
    "banner320x48",
    "banner300x250",
}
if sysModel == "iPad" then
    -- change settings if on iPad. It has 3 additional adUnitTypes it can show.
    bgW, bgH = 768, 1024
    adsTable = {
        "banner320x48",
        "banner300x250",
        "banner728x90",
        "banner468x60",
        "banner120x600"
    }
end

-- localize a widget function
local newButton = require( "widget" ).newButton

-- change settings if on iPad
if sysModel == "iPad" then
    bgW, bgH = 768, 1024
end

-- create a background for the app
local backgroundImg = display.newImageRect( "space.png", bgW, bgH )
backgroundImg:setReferencePoint( display.TopLeftReferencePoint )
backgroundImg.x, backgroundImg.y = 0, 0


if appID then
    -- Shows the banner indexed by variable "currentAdIndex"
    local showIndexedBanner = function()
        print("Showing Banner: " .. adsTable[currentAdIndex])
        local adX, adY = 0, 0
        ads.show( adsTable[currentAdIndex], { x=adX, y=adY, interval=5, testMode=true } )
    end

    -- onRelease event listener for 'nextButton'
    local onNextButtonReleased = function( event )
        currentAdIndex = currentAdIndex + 1
        if (currentAdIndex > #adsTable) then
            currentAdIndex = 1
        end
        showIndexedBanner()
    end

    -- onRelease event listener for 'hideButton'
    local onHideButtonReleased = function( event )
        ads.hide()
    end

    -- if on simulator, make sure onRelease event for buttons are set to nil
    if sysEnv == "simulator" then
        onNextButtonReleased = nil
        onHideButtonReleased = nil
    end

    -- create a next button (to show a different ad unit)
    local nextButton = newButton{
        default="button.png",
        over="button_over.png",
        label = "Show Next Banner",
        onRelease= onNextButtonReleased
    }
    nextButton:setReferencePoint( display.CenterReferencePoint )
    nextButton.x = display.contentWidth * 0.5
    nextButton.y = display.contentHeight - 120

    -- create a hide button
    local hideButton = newButton{
        default="button.png",
        over="button_over.png",
        label = "Hide Banner",
        onRelease= onHideButtonReleased
    }
    hideButton:setReferencePoint( display.CenterReferencePoint )
    hideButton.x = display.contentWidth * 0.5
    hideButton.y = display.contentHeight - 60

    -- if on simulator, let user know they must build for device
    if sysEnv == "simulator" then
       
        local font, size = "Helvetica-Bold", 22
       
        local warningText1 = display.newText( "Please build for device ", 0, 135, font, size )
        local warningText2 = display.newText( "to test this sample code.", 0, 165, font, size )
       
        warningText1:setTextColor( 255, 255, 255, 255 )
        warningText2:setTextColor( 255, 255, 255, 255 )
       
        warningText1:setReferencePoint( display.CenterReferencePoint )
        warningText2:setReferencePoint( display.CenterReferencePoint )
       
        local halfW = display.contentWidth * 0.5
        warningText1.x, warningText2.x = halfW, halfW
       
        -- make buttons appear disabled
        nextButton.view.alpha = 0
        hideButton.view.alpha = 0
    else
        -- display initial banner ad
        showIndexedBanner()
    end
else
    -- If no appId is set, show a message on the screen
    local font, size = "Helvetica-Bold", 22

    local warningText1 = display.newText( "No appID has been set.", 0, 105, font, size )
    warningText1:setTextColor( 255, 255, 255, 255 )
    warningText1:setReferencePoint( display.CenterReferencePoint )

    local halfW = display.contentWidth * 0.5
    warningText1.x = halfW

    if sysEnv == "simulator" then
        local warningText2 = display.newText( "Please build for device ", 0, 185, font, size )
        local warningText3 = display.newText( "to test this sample code.", 0, 215, font, size )
        warningText2:setTextColor( 255, 255, 255, 255 )
        warningText3:setTextColor( 255, 255, 255, 255 )

        warningText2:setReferencePoint( display.CenterReferencePoint )
        warningText3:setReferencePoint( display.CenterReferencePoint )
        warningText2.x, warningText3.x = halfW, halfW
    end
end

이 샘플 코드는 Show Next Banner를 누르면 해당 디바이스에서 보일 수 있는 배너 크기별 광고를 차례대로 보여줍니다.
그리고 Hide Banner를 누르면 이 배너를 감춥니다.

코드를 라인별로 분석해 볼까요?
(아래 압축파일에 원본소스와 이미지 등이 있습니다.)



우선 주석은 다 지나가고 34번째 줄부터 시작합니다. 이 줄은 아이폰의 statusBar를 없애는 부분입니다.
39번째 줄에 adNetwork라는 변수에 inmobi라는 값을 담았습니다.
그리고 appID에 inmobi에서 받은 값을 넣어야 하는데요. 위 소스는 nil로 돼 있어서 저는 테스트용 id를 넣었습니다. "4028cb962895efc50128fc99d4b7025b"

그 다음 49번째 줄에서 ads를 require 했고 다음 줄(52)에서 appID가 nil이 아니면 ads.init을 해 줍니다.

그리고 sysModel에 디바이스의 모델을 그리고 sysEnv에 디바이스의 environment를 담습니다.

61번째 줄을 보면 bgW,bgH를 아이폰 해상도에 맞게 320,480 으로 정합니다.
다음줄에 currentAdIndex 에 1을 대입합니다.

다음 adsTable이라는 테이블에 아이폰에서 가능한 배너크기 두가지를 넣습니다.
그리고 sysModel이 iPad 이면 bgW,bgH에 768,1024 를 대입하고 adsTable에는 5종류의 배너크기 모두를 대입합니다.

82번째 줄은 newButton을 wedget의 버튼으로 선언합니다.

85~88번째 줄은 iPad일 경우 bgW,bgH를 바꿔 주는 부분인데요. 70번째 줄에서 이미 한 작업인데 여기서 또 하네요. 이건 없애도 되겠습니다.

다음 92~94째줄은 backgroundImg를 세팅해 주는 부분입니다.

이제 다음부터 어떤 로직이 나오나 봅니다. (저도 지금 이거 처음 보면서 작성하는 거라서 뭐가 나올지 모릅니다.)

appID가 있으면  local showIndexedBanner 함수를 선언하는데요. adX,adY를 0,0으로 하고 ads.show()를 통해서 광고를 보여줍니다.

그 다음 onNextButtonReleased 함수가 있는데 파라미터로 event를 받는 거로 봐서 어떤 리스너에서 호출할 건가 봅니다.
여기서는 currentAdIndex에 1을 더해주고 adsTable의 요소보다 커지게 되면 다시 currentAdIndex를 1로 해주는 로직이 있구요.
이 작업이 끝나면 showIndexedBanner()를 호출합니다.

그러니까 어떤 버튼이 클릭되면 currentAdIndex를 바꿔서 showIndexedBanner()함수를 호출하니까 adsTable에 있는 배너 종류가 차례대로 보이겠네요.

그 다음 117번째 줄은 onHideButtonReleased 함수가 있는데 이것도 event 파라미터가 있는 걸로 봐서 리스너에서 호출 할 겁니다.
당연히 hide ads버튼에서 호출하겠죠?
이 함수가 호출되면 ads.hide()를 실행 시켜서 광고를 없앱니다.

그 다음 123번째 줄은 sysEnv가 시뮬레이터면 onNextButtonReleased와 onHideButtonReleased 함수를 모두 없앱니다.

130번째 줄 nextButton 에는 default button image와 over시 버튼 이미지를 정해주고 글자를 Show Next Banner라고 정해 줍니다. onRelease 에는 onNextButtonReleased를 대입해 줍니다.
그리고 그 위치를 정해 주고요.
142번째 줄에서는 hideButton을 선언해주고 위치를 정해 줍니다.

154번째 줄에서는 sysEnv가 시뮬레이터 이면 warningText1,warningText2를 뿌려줍니다.
그리고 두개의 버튼에 투명도를 주어서 안 보이도록 합니다.
시뮬레이터가 아니면 showIndexedBanner()를 실행 시켜서 광고를 보여줍니다.
버튼에 투명도 처리하는 부분도 적용 안 되니까 이 경우엔 버튼도 보이겠죠?

177번째 줄은 저 위에 있는 if문하고 연결 됩니다 뭐냐하면 97번째 줄의 if appID then 요.

만약 appID가 없다면 97번째 이후에 있던 코드는 다 실행하지 않고 181번째 줄에 있는 warningText1을 화면에 표시합니다.
그리고 시뮬레이터 이면 warningText2,warningText3를 출력합니다.

여기까지가 이 소스코드를 모두 분석한 내용입니다.

제가 iPod Touch에서 겪었던 에러 (화면 뜨고 광고가 뜨기 전에 화면이동-director.lua- 할 경우 생기는) 를 해결 할 수 있는 부분은 없네요.

아직 코로나에서 미처 대응하지 못했던 에러가 아닌가 합니다.
iPhone이나 그 이후 버전의 phone이나 iPad에서는 이러한 현상이 일어나는지 어떤지 잘 모르겠습니다.

이거 회사 테스트 디바이스 지원이 너무 열악해요...

하여간 오늘은 간단히 소켓통신에 대해 알아봤구요.
그리고 코로나에서의 광고 띄우기 (inMobi) 에 대해 자세히 알아봤습니다.

다음엔 네트워킹과 web service에 대해 마저 알아볼 건데요.
요즘 제가 관심 가지고 있는 In-App Purchases 에 대해서도 있네요.

시간이 허락되면 여기까지 다 공부 하겠습니다.

반응형

오디오, 비디오, 사진 컨트롤 2

2011. 10. 20. 22:51 | Posted by 솔웅


반응형
비디오 라이브러리

비디오 파일 플레이는 media.playVideo 함수로 구현 되고 이것은 비동기적입니다.
비디오가 끝나거나 유저가 끝낼을 때 어떤 핸들링을 하려면 onComplete를 사용합니다.
local onComplete = function(event)
   print( "video session ended" )
end
media.playVideo( "Movie.m4v", true, onComplete )
비디오 파일 플레이는 remote URL을 이용해 상영할 수도 있습니다.
신택스는 아래와 같습니다.
media.playVideo( path [, baseSource ], showControls, listener )

baseSource 부분은 옵션으로 디폴트는 system.ResourceDirectory입니다. URL을 넣을 수도 있습니다.

코로나에서 샘플로 제공하는 샘플 코드인 StreamingVideo 소스 코드를 보면 아래와 같습니다.

display.setStatusBar( display.HiddenStatusBar )   -- 아이폰의 StatusBar를 없앤다.
local posterFrame = display.newImage( "Default.png" )
function posterFrame:tap( event ) -- posterFrame이미지를 tap하면 실행되는 함수
    msg.text = "Video Done"        -- message will appear after the video finishes
    media.playVideo( "http://www.anscamobile.com/video/Corona-iPhone.m4v", media.RemoteSource, true )
end
-- Determine if running on Corona Simulator
-- 현재 device가 simulator인지 체크 함
local isSimulator = "simulator" == system.getInfo("environment")
-- Video is not supported on Simulator
if isSimulator then -- 시뮬레이터라면 이 메세지를 화면에 뿌림
    msg = display.newText( "No Video on Simulator!", 0, 60, "Verdana-Bold", 22 )
else -- 시뮬레이터가 아니면 아래 메세지를 뿌림
    msg = display.newText( "Tap to start video", 0, 60, "Verdana-Bold", 22 )
    posterFrame:addEventListener( "tap", posterFrame )        -- add Tap listener
end
msg.x = display.contentWidth/2        -- center title
msg:setTextColor( 0,0,255 )



비디오 파일 플레이하는것도 보시다시피 아주 간단합니다.

코로나에서 지원하는 비디오파일 포맷은 아래와 같습니다.
.mov, .mp4, .m4v, .3gp

카메라와 사진 라이브러리

media.show(imageSource,listener)
imageSource 부분엔 아래 세가지 중 하나가 들어갑니다.
media.PhotoLibrary
media.Camera
media.SavedPhotosAlbum

이 함수는 비동기적입니다. 그 의미는 이 함수 다음에 어떤 메소드(함수)가 있다면 이 함수가 끝난 이후에 실행 될거라는 겁니다.
아래 소스를 참고하세요.
local onComplete = function(event)
   local photo = event.target
   print( "photo w,h = " .. photo.width .. "," .. photo.height )
end
media.show( media.Camera, onComplete )

Event Sounds

media 라이브러리는 재생을 위해  아래기능을 지원합니다.
event sounds : 짧은 소리, 전체가 재생 됨
extended sounds : 긴 소리. 재생 기간 동안 정지 할 수도 있음. 한번에 하나만 open 할 수 있음

Event Sounds

1~3초 정도의 짧은 소리가 있다면 event sound API를 사용하는 것이 좋습니다.
local soundID = media.newEventSound( "beep.caf" )
 
local playBeep = function()
        media.playEventSound( soundID )
end
timer.performWithDelay( 1000, playBeep, 0 )

이 사운드 파일은 media.newEventSound를 통해 한번 로딩 된 후 여러번 반복해서 사용 될 수 있습니다.

media.newEventSound(soundFile) : soundFile로부터 sound를 로딩합니다. 그리고 sound id 이벤트를 리턴합니다. 이것은 media.playEventSound에 전달 될 인수입니다.
media.playEventSound(sound) : 사운드를 재생합니다.

안드로이드에서는 사운드를 로딩하고 준비하는데 약간의 딜레이가 있을 수 있습니다. 그러므로 playEventSound에 filename 파라미터를 사용하는 것은 추천하지 않습니다. newEventSound로 미리 로딩해서 사용하세요.

playEventSound 안에 아래와 같이 함수를 지정할 수 있습니다.
media.playEventSound("beef.caf",onComplete)
이렇게 되면 플레이가 끝난 이후 onComplete함수를 실행합니다.

Extended Sounds

좀 긴 사운드 (아이폰에서의 MP3 포맷이나 배경음악 재생같은)에 사용됩니다.
play,pause,stop같은 기능들이 있습니다.

media.playSound( "song.mp3" )
 
local stopAfter10Seconds = function()
        media.stopSound()
end
timer.performWithDelay( 10000, stopAfter10Seconds )

media.stopSound()와 media.playSound(soundFile) 은 위에 있구요.
이외에 media.pauseSound() 도 있습니다.

아주 큰 사운드 파일일 경우는 로딩하는데 시간이 오래 걸릴 수 있습니다. 이 경우 애니메이션이 실행 되고 있다면 잠깐 중단 될 수도 있습니다. 이를 방지 하기 위해서 애니메이션이 실행되기 이전에 로딩해 둘 수 있겠죠?

media.playSound( 'sound.mp3' )
media.stopSound()

이렇게 play시켰다가 곧바로 stop 시키면 미리 로딩을 시킬 수 있을 겁니다.
어쩐지 좀 꼼수 같죠? 코로나 Doc에서 정식으로 이 방법을 소개하고 있네요.

아래와 같이 사운드 종료시 다른 함수를 실행 시키도록 할 수 있습니다.
local onComplete
onComplete = function(event)
        print( "sound play ended" )
        media.playSound( "note2.mp3", onComplete )
end
 
media.playSound( "note2.mp3", onComplete )

이 코드는 note2.mp3가 끊이지 않고 계속 루핑되면서 재생되는 효과가 있겠네요.
루핑기능을 위한 꼼수로 보이네요.

Loop Parameter
media.playSound("note2.mp3", true)
이렇게 마지막에 true 파라미터를 주면 사운드를 계속 반복 재생시켜줍니다.
이 방법이 조 위에 있는 방법보다 부담을 덜 줄겁니다.

media.setSoundVolume(0.5)
print("volume = "  .. media.getSoundVolume())
위와 같이 볼륨 조절이 가능합니다.

event sound에는 기 볼륨조절 기능이 지원이 안 됩니다. 이건 iPhone API에서 제공하지 않는다고 하네요.

코로나 SDK에서 지원하는 Audio Format들은 아래와 같습니다.
event sound file
- 수초 이내의 짧은 시간이어야 한다.
- PCM,IMA4(IMA/ADPCM) 포맷
- .caf나 .aif 파일
media.playSound()를 이용하는 좀 더 긴 파일은 mp3파일을 지원 합니다.

녹음 기능
recording = media.newRecording([file])
recording:startRecording()
recording:stopRecording()

녹음에는 이런 기능들이 제공 됩니다.
이건 시뮬레이터나 iPod Touch 같이 하드웨어에 마이크(녹음) 기능이 없으면 테스트가 불가능하겠죠.
그러면 빌드를 해서 직접 폰에서 테스트를 해야 할 텐데 그러려면 코로나 유료버전을 사야 되구요.
테스트 하기엔 좀 제한이 있네요.

result = recording:isRecording()
현재 녹음 되고 있다면 true를 그렇지 않으면 false를 반환합니다.

recording:setSampleRate() ; rate = recording:getSampleRate()

디폴트는 44100dlqslek. 8000,11025,16000,22050,44100 Rate 등이 검증 된 수치들 입니다.
startTuner()를 하기 전에 반드시 이 setSampleRate()를 불러와야 합니다.
사운드 관련된 전문 앱을 만드려면 이런걸 신경 쓰셔야 겠지만 또 하드웨어 적으로 지원이 안되면 이것도 한계가 있을 겁니다.

Audio Tuner
recording:startTuner()
tuning을 할 수 있도록 합니다.

freq = recording:getTunerFrequency()
Hz 를 반환합니다. 이 기능은 tuner가 on 인 상태에서만 작동 됩니다.

recording:stopTuner() : tuner를 정지 합니다.

volume = recording:getTunerVolume()
최근에 확정된 볼륨 숫자를 반환합니다. 범위가 -1에서 1사이로 나온다고 하는데요.
이것을 알기 쉽게 보려면 10*math.log(volume)을 통해서 보는게 좋습니다.

자 그럼 Corona SDK 의 Media 기능에 대해 다 훑어 봤습니다.

이제 남은 주제들은 Networking and Web Service, System and OS, Interactivityand Detecting Events, Location and Maps, Native UI, Advanced Programming Techniques 등이 남았네요.

꽤 많이 한것 같은데 아직 다뤄야 할 이슈들이 많습니다.
부지런히 다루고 그 다음은 샘플 코드들을 분석해 볼까 합니다.
여러가지 TIP들도 많이 다뤄보구요.

다음 시간에 뵐께요.


 

반응형