Live update - kuimoani/defold GitHub Wiki

Live update

κ²Œμž„μ„ λ²ˆλ“€(bundle)둜 λ§Œλ“€ λ•Œ, DefoldλŠ” λͺ¨λ“  κ²Œμž„ λ¦¬μ†ŒμŠ€λ“€ ν”Œλž«νΌ 별 νŒ¨ν‚€μ§€λ‘œ λ¬ΆμŠ΅λ‹ˆλ‹€. λŒ€λΆ€λΆ„μ˜ κ²½μš°μ—λŠ” μ—”μ§„ μ‹€ν–‰ 후에 μ¦‰μ‹œ λͺ¨λ“  λ¦¬μ†ŒμŠ€μ— μ ‘κ·Όν•΄μ„œ μŠ€ν† λ¦¬μ§€λ‘œλΆ€ν„° μ‹ μ†ν•˜κ²Œ λ‘œλ“œν•˜λŠ” 것을 μ„ ν˜Έν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ λ¦¬μ†ŒμŠ€ λ‘œλ”©μ„ λ‚˜μ€‘μœΌλ‘œ λ―Έλ£¨λŠ” 것을 원할 κ²½μš°λ„ μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄,

  • λ‹Ήμ‹ μ˜ κ²Œμž„μ€ μ—ν”Όμ†Œλ“œ μ‹œλ¦¬μ¦ˆλ₯Ό νŠΉμ§•μœΌλ‘œ κ°€μ§€κ³  있으며, μœ μ €κ°€ κ²Œμž„μ˜ λ‚˜λ¨Έμ§€ 뢀뢄을 계속 ν• μ§€λ₯Ό κ²°μ •ν•˜κΈ° 이전에 ν”Œλ ˆμ΄μ–΄κ°€ ν”Œλ ˆμ΄ ν•  수 μžˆλŠ” 첫 번째 판만 ν¬ν•¨λ˜μ–΄ 있기λ₯Ό μ›ν•œλ‹€.

  • λ‹Ήμ‹ μ˜ κ²Œμž„μ€ HTML5λ₯Ό νƒ€κ²ŸμœΌλ‘œ ν•˜κ³  μžˆλ‹€. μŠ€ν† λ¦¬μ§€μ—μ„œ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ‘œλ”©ν•œλ‹€λŠ” 것은 λΈŒλΌμš°μ €μ—μ„œ 전체 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ νŒ¨ν‚€μ§€λ₯Ό λ‹€μš΄λ‘œλ“œ ν•΄μ•Ό ν•œλ‹€λŠ”κ²ƒμ„ λœ»ν•œλ‹€. μ΄λŸ¬ν•œ ν”Œλž«νΌμ—μ„œλŠ” κ²Œμž„ λ¦¬μ†ŒμŠ€μ˜ λ‚˜λ¨Έμ§€λ₯Ό λ‹€μš΄λ‘œλ“œ ν•˜κΈ° 전에 μ΅œμ†Œν•œμ˜ μ‹œμž‘ νŒ¨ν‚€μ§€λ₯Ό λ³΄λ‚΄μ„œ 앱을 λΉ λ₯΄κ²Œ μ‹€ν–‰ν•˜λŠ” 것이 λ‚˜μ„μ§€λ„ λͺ¨λ₯Έλ‹€.

  • λ‹Ήμ‹ μ˜ κ²Œμž„μ—λŠ” κ²Œμž„μ— ν‘œμ‹œλ  λ•ŒκΉŒμ§€ λ‹€μš΄λ‘œλ“œλ₯Ό μ—°κΈ°ν•˜λ €λŠ” μ•„μ£Ό 큰 λ¦¬μ†ŒμŠ€λ“€(이미지, λ™μ˜μƒ λ“±)이 ν¬ν•¨λ˜μ–΄ μžˆλ‹€. 이것은 μΈμŠ€ν†¨ μ‚¬μ΄μ¦ˆλ₯Ό 쀄이기 μœ„ν•¨μ΄λ‹€.

라이브 μ—…λ°μ΄νŠΈ κΈ°λŠ₯은 λΉŒλ“œμ‹œμ— λ²ˆλ“€μ—μ„œ μ˜λ„μ μœΌλ‘œ μ œμ™Έν•œ λ¦¬μ†ŒμŠ€λ“€μ„ λŸ°νƒ€μž„μ‹œ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ λ²ˆλ“€λ‘œ λ¦¬μ†ŒμŠ€λ₯Ό λΆˆλŸ¬μ™€ μ €μž₯ν•˜κ²Œ ν•΄μ£ΌλŠ” λ©”μ»€λ‹ˆμ¦˜μ΄λ©°, 이λ₯Ό μ‚¬μš©ν•˜μ—¬ μ»¬λ ‰μ…˜ ν”„λ‘μ‹œμ˜ 컨셉을 ν™•μž₯ν•©λ‹ˆλ‹€.

Preparing content for Live update

μš°λ¦¬κ°€ 큰 고해상도 이미지 λ¦¬μ†ŒμŠ€λ“€μ„ ν¬ν•¨ν•œ κ²Œμž„μ„ λ§Œλ“€κ³  μžˆλ‹€κ³  κ°€μ •ν•΄ λ΄…μ‹œλ‹€. 이 κ²Œμž„μ€ 이 이미지듀을 μŠ€ν”„λΌμ΄νŠΈ κ²Œμž„ μ˜€λΈŒμ νŠΈμ— λ„£μ–΄ μ»¬λ ‰μ…˜μ—μ„œ μœ μ§€ μ‹œν‚€λ €κ³  ν•©λ‹ˆλ‹€.

Mona Lisa collection

μ΄λŸ¬ν•œ μ»¬λ ‰μ…˜μ„ λ™μ μœΌλ‘œ λ‘œλ“œν•˜λ €λ©΄, κ°„λ‹¨ν•˜κ²ŒλŠ” μ»¬λ ‰μ…˜ ν”„λ‘μ‹œ μ»΄ν¬λ„ŒνŠΈλ₯Ό μΆ”κ°€ν•˜κ³  "monalisa.collection"λ₯Ό μ§€μ •ν•˜λ©΄ λ©λ‹ˆλ‹€. 이제 κ²Œμž„μ€ "load" λ©”μ„Έμ§€λ₯Ό μ»¬λ ‰μ…˜ ν”„λ‘μ‹œλ‘œ λ³΄λ‚΄μ„œ μŠ€ν† λ¦¬μ§€μ—μ„œ λ©”λͺ¨λ¦¬λ‘œ μ»¬λ ‰μ…˜μ— μžˆλŠ” 컨텐츠λ₯Ό μ–Έμ œ λ‘œλ“œν• μ§€ 선택할 수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μš°λ¦¬λŠ” ν•œ 발 더 λ‚˜μ•„κ°€μ„œ μ»¬λ ‰μ…˜μ— ν¬ν•¨λœ λ¦¬μ†ŒμŠ€μ˜ λ‘œλ”©μ„ μ œμ–΄ν•˜λ €κ³  ν•©λ‹ˆλ‹€.

이 μž‘μ—…μ€ μ»¬λ ‰μ…˜ ν”„λ‘μ‹œ ν”„λ‘œνΌν‹°μ˜ Exclude μ²΄ν¬λ°•μŠ€λ₯Ό μ²΄ν¬ν•˜λ©΄, μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ λ²ˆλ“€μ„ μƒμ„±ν• λ•Œ λ²ˆλ“€λŸ¬(bundler)μ—κ²Œ "monalisa.collection"의 λͺ¨λ“  컨텐츠λ₯Ό 남겨 달라고 말해 쀌으둜써 μˆ˜ν–‰λ©λ‹ˆλ‹€.

Collection proxy excluded

Live update settings

λ²ˆλ“€λŸ¬κ°€ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ λ²ˆλ“€μ„ μƒμ„±ν• λ•Œ, μ œμ™Έ 된 λ¦¬μ†ŒμŠ€λ₯Ό μ–΄λ”˜κ°€μ—λŠ” μ €μž₯ν•΄μ•Ό ν•©λ‹ˆλ‹€. 라이브 μ—…λ°μ΄νŠΈλ₯Ό μœ„ν•œ ν”„λ‘œμ νŠΈ μ…‹νŒ…μ€ 이듀 λ¦¬μ†ŒμŠ€λ“€μ˜ μœ„μΉ˜λ₯Ό λ‹€λ£Ήλ‹ˆλ‹€. 이 μ…‹νŒ…μ€ Project β–Έ Live update Settings… μ—μ„œ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.

Live update settings

μ—¬κΈ°μ—” Defoldκ°€ 섀정을 μ €μž₯ν•  수 μžˆλŠ” 두 κ°€μ§€ 방법이 μžˆμŠ΅λ‹ˆλ‹€. 라이브 μ—…λ°μ΄νŠΈ μ…‹νŒ… μ°½μ—μ„œ Mode λ“œλ‘­λ‹€μš΄ λ²„νŠΌμ„ μ—΄μ–΄ μ €μž₯ 방식을 선택해 λ³΄μ„Έμš”.

Amazon

이 μ˜΅μ…˜μ€ Defoldμ—κ²Œ μ•„λ§ˆμ‘΄ μ›Ή μ„œλΉ„μŠ€(AWS) S3 버켓에 μ œμ™Έλœ λ¦¬μ†ŒμŠ€λ₯Ό μžλ™μœΌλ‘œ μ—…λ‘œλ“œ ν•˜λΌκ³  μ§€μ‹œν•©λ‹ˆλ‹€. AWS Credential profile 에 이름을 μž…λ ₯ν•˜κ³  μ λ‹Ήν•œ Bucketκ³Ό Prefix λ₯Ό μ„ νƒν•˜μ„Έμš”. AWS 계정을 μ…‹μ—…ν•˜λŠ” μžμ„Έν•œ 방법은 μ•„λž˜μ—μ„œ 확인해 μ£Όμ„Έμš”.

Zip

이 μ˜΅μ…˜μ€ Defoldμ—κ²Œ μ œμ™Έλœ λ¦¬μ†ŒμŠ€λ₯Ό ν¬ν•¨ν•œ Zip μ••μΆ• νŒŒμΌμ„ μƒμ„±ν•˜λΌκ³  μ§€μ‹œν•©λ‹ˆλ‹€. 이 μ••μΆ• νŒŒμΌμ€ Export path에 μ„€μ •ν•œ κ²½λ‘œμ— μ €μž₯λ©λ‹ˆλ‹€.

Scripting with excluded collection proxies

λ²ˆλ“€λ§(bundling)μ—μ„œ μ œμ™Έλœ μ»¬λ ‰μ…˜ ν”„λ‘μ‹œλŠ” 일반적인 μ»¬λ ‰μ…˜ ν”„λ‘μ‹œ 처럼 λ™μž‘ν•©λ‹ˆλ‹€. ν•˜λ‚˜μ˜ μ€‘μš”ν•œ μ°¨μ΄μ μœΌλ‘œλŠ” λ²ˆλ“€ μŠ€ν† λ¦¬μ§€μ—μ„œ μ‚¬μš©ν•  수 μ—†λŠ” λ¦¬μ†ŒμŠ€κ°€ μžˆλ‹€λ©΄, "load" λ©”μ„Έμ§€λ₯Ό μ „μ†‘ν•˜λŠ” 것이 μ‹€νŒ¨ν•˜κ²Œ λœλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

κ·ΈλŸ¬λ―€λ‘œ "load" λ©”μ„Έμ§€λ₯Ό 보내기 전에, λˆ„λ½λœ λ¦¬μ†ŒμŠ€κ°€ μžˆλŠ”μ§€ 확인해야 ν•˜λ©°, λˆ„λ½λœ λ¦¬μ†ŒμŠ€κ°€ μ—†λ‹€λ©΄ λ‹€μš΄λ‘œλ“œ ν›„ μ €μž₯ν•˜λ©΄ λ©λ‹ˆλ‹€. λ‹€μŒμ€ λ¦¬μ†ŒμŠ€κ°€ μ•„λ§ˆμ‘΄ S3에 "my-resources"λΌλŠ” prefix와 "my-game-bucket" λΌλŠ” bucket으둜 μ €μž₯λ˜μ–΄ μžˆλ‹€κ³  κ°€μ •ν•œ 예제 μ½”λ“œμž…λ‹ˆλ‹€.

function init(self)
    self.resources_pending = 0                                 [1]
    msg.post("#", "attempt_load_resources")
end

-- 이 ν•¨μˆ˜λŠ” μ»¬λ ‰μ…˜ ν”„λ‘μ‹œλ₯Ό λ‘œλ“œν•˜λŠ”λ° ν•„μš”ν•œ λ‹€μš΄λ‘œλ“œλœ λ¦¬μ†ŒμŠ€λ₯Ό μ €μž₯ν•˜λ € ν•  λ•Œλ§ˆλ‹€ 호좜 λ©λ‹ˆλ‹€.
local function resource_store_response(self, hexdigest, status)
    if status == true then
        -- λ¦¬μ†ŒμŠ€λ₯Ό μ„±κ³΅μ μœΌλ‘œ λ‘œλ“œν•¨
        print("Resource data stored: " .. hexdigest)

        -- λ‹€μŒ λ¦¬μ†ŒμŠ€λ₯Ό μœ„ν•΄ ν•˜λ‚˜ λΉΌκΈ°...
        self.resources_pending = self.resources_pending - 1

        -- μ „λΆ€ μ„±κ³΅μ μœΌλ‘œ μ €μž₯됨, 이제 ν”„λ‘μ‹œ μ»¬λ ‰μ…˜μ„ λ‘œλ“œν•  λ•Œκ°€ 됨
        if self.resources_pending == 0 then
            msg.post("#proxy", "load")            [8]
        end
    else
        -- ERROR! 데이터 μ €μž₯ μ‹€νŒ¨!
        print("Failed to store resource data: " .. hexdigest)
    end
end

function on_message(self, message_id, message, sender)
    if message_id == hash("attempt_load_resources") then
        local missing_resources = collectionproxy.missing_resources("#proxy")            [2]

        -- 아직 μ‹œλ„ν•˜μ§€ μ•Šμ€ λˆ„λ½λœ λ¦¬μ†ŒμŠ€λ₯Ό μœ„ν•΄ λ‹€μš΄λ‘œλ“œ μš”μ²­μ„ κ°œμ‹œν•¨
        for _,resource_hash in ipairs(missing_resources) do
            msg.post("#", "attempt_download", { resource_hash = resource_hash})
        end

        self.resources_pending = #missing_resources            [3]

        -- λ§Œμ•½ μ—λ””ν„°μƒμ—μ„œ μ‹€ν–‰ν•˜λŠ”κ±°λ©΄ λͺ¨λ“  λ¦¬μ†ŒμŠ€κ°€ 이미 λ‘œλ“œλœκ±°λ‘œ 됨
        if self.resources_pending == 0 then
            msg.post("#proxy", "load")
        end
    elseif message_id == hash("attempt_download") then
        local manifest = resource.get_current_manifest()            [4]
        local base_url = "https://my-game-bucket.s3.amazonaws.com/my-resources/"            [5]
        http.request(base_url .. message.resource_hash, "GET", function(self, id, response)
                if response.status == 200 or response.status == 304 then            [6]
                    -- ok둜 응닡(response) λ°›μŒ
                    print("storing " .. message.resource_hash)
                    resource.store_resource(manifest, response.response, message.resource_hash, resource_store_response)            [7]
                else
                    -- ERROR! λ¦¬μ†ŒμŠ€ λ‹€μš΄λ‘œλ“œ μ‹€νŒ¨!
                    print("Failed to download resource: " .. message.resource_hash)
                end
            end)
    elseif message_id == hash("proxy_loaded") then
        msg.post(sender, "init")
        msg.post(sender, "enable")
    end
end
  • [1] ν”„λ‘μ‹œ μ»¬λ ‰μ…˜μ„ λ‘œλ“œν•˜κΈ° 전에 μ–Όλ§ˆλ‚˜ λ§Žμ€ λ¦¬μ†ŒμŠ€λ₯Ό λ‹€μš΄λ‘œλ“œ ν•˜κ³  μ €μž₯ν•΄μ•Ό ν•˜λŠ”μ§€ μ•Œλ €μ£ΌλŠ” κ°„λ‹¨ν•œ μΉ΄μš΄ν„°. 이 μ½”λ“œλŠ” μ—λŸ¬λ₯Ό μ „ν˜€ μ²˜λ¦¬ν•˜μ§€ μ•Šκ³  μžˆμœΌλ―€λ‘œ μ‹€μ œ μ œν’ˆμš© μ½”λ“œμ—μ„œλŠ” λ‹€μš΄λ‘œλ“œμ™€ μ €μž₯ μž‘μ—…μ‹œ 더 λ§Žμ€ μ²˜λ¦¬κ°€ ν•„μš”ν•¨.
  • [2] λ‹€μš΄λ‘œλ“œμ™€ μ €μž₯이 ν•„μš”ν•œ λͺ¨λ“  λ¦¬μ†ŒμŠ€λ“€μ„ νšλ“ν•¨
  • [3] λˆ„λ½λœ λ¦¬μ†ŒμŠ€λ“€μ˜ 수λ₯Ό μ €μž₯ν•΄μ„œ 카운트 λ‹€μš΄ 함
  • [4] λ²ˆλ“€μ˜ λͺ¨λ“  λ¦¬μ†ŒμŠ€λ“€μ„ λ‚˜μ—΄ν•˜κ³  μ‚¬μš©κ°€λŠ₯ μ—¬λΆ€λ₯Ό ν™•μΈν•œ μ΄ν›„μ˜ ν˜„μž¬ λ©”λ‹ˆνŽ˜μŠ€νŠΈκ°€ ν•„μš”ν•¨
  • [5] λ¦¬μ†ŒμŠ€λ₯Ό μ•„λ§ˆμ‘΄ S3 에 μ €μž₯함. λ§Œμ•½ Zip 파일둜 μ €μž₯ν•œλ‹€λ©΄, νŒŒμΌμ„ μ–΄λ”˜κ°€μ— ν˜ΈμŠ€νŒ…ν•˜κ³  http.request()둜 λ‹€μš΄λ‘œλ“œ ν•  λ•Œ 파일의 μœ„μΉ˜λ₯Ό μ°Έμ‘°ν•΄μ•Ό 함
  • [6]. 파일이 ν¬λž˜μ‰¬ λ‚˜λ©΄ μ•„λ§ˆμ‘΄μ΄ 304 statusλ₯Ό 리턴함
  • [7]. 데이터λ₯Ό λ“€κ³  μžˆμœΌλ―€λ‘œ μ €μž₯을 μ‹œλ„ν•¨
  • [8]. μŠ€ν† λ¦¬μ§€μ— μ„±κ³΅μ μœΌλ‘œ μ €μž₯ν–ˆμœΌλ©΄ λ¦¬μ†ŒμŠ€ μΉ΄μš΄ν„°κ°€ 0이 됨. 이제 μ»¬λ ‰μ…˜ ν”„λ‘μ‹œμ— "load" λ©”μ„Έμ§€λ₯Ό 보내도 μ•ˆμ „ν•¨. νŠΉμ • μ§€μ μ—μ„œ λ‹€μš΄λ‘œλ“œλ‚˜ μ €μž₯이 μ‹€νŒ¨ν•œ κ²½μš°μ—” λ¦¬μ†ŒμŠ€ μΉ΄μš΄ν„°κ°€ 0이 될 수 μ—†μŒ

μœ„μ˜ λ‘œλ”© μ½”λ“œλ₯Ό μ‚¬μš©ν•΄μ„œ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ ν…ŒμŠ€νŠΈ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ—λ””ν„°μƒμ—μ„œ μ‹€ν–‰ν•˜λ©΄ 아무것도 λ‹€μš΄λ‘œλ“œ ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ 라이브 μ—…λ°μ΄νŠΈλŠ” λ²ˆλ“€(bundle)의 κΈ°λŠ₯이기 λ•Œλ¬Έμž…λ‹ˆλ‹€. 에디터 ν™˜κ²½μ—μ„œ μ‹€ν–‰ν•˜λ©΄ μ–΄λ–€ λ¦¬μ†ŒμŠ€λ„ μ œμ™Έ(exclude)λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이 λ™μž‘μ΄ 잘 λŒμ•„κ°€λŠ”μ§€ ν™•μΈν•˜λ €λ©΄, λ²ˆλ“€λ‘œ λ§Œλ“€μ–΄μ„œ μ‹€ν–‰ν•΄μ•Ό ν•©λ‹ˆλ‹€.

Bundling with Live update

라이브 μ—…λ°μ΄νŠΈλ₯Ό μ΄μš©ν•΄ λ²ˆλ“€μ„ λ§Œλ“œλŠ” 것은 μ‰½μŠ΅λ‹ˆλ‹€. Project β–Έ Bundle 메뉴λ₯Ό μ„ νƒν•˜κ³  μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ λ²ˆλ“€μ„ λ§Œλ“€κΈ° μ›ν•˜λŠ” ν”Œλž«νΌμ„ μ„ νƒν•˜λ©΄ λ²ˆλ“€λ§ λ‹€μ΄μ–Όλ‘œκ·Έ 창이 μ—΄λ¦½λ‹ˆλ‹€.

Bundle Live application

λ²ˆλ“€λ§(dundling) ν•  λ•Œ, μ œμ™Έ λ¦¬μ†ŒμŠ€(excluded resource)듀은 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ λ²ˆλ“€μ—μ„œ μ œμ™Έλ©λ‹ˆλ‹€. Publish Live update content μ²΄ν¬λ°•μŠ€λ₯Ό μ²΄ν¬ν•˜λ©΄ 라이브 μ—…λ°μ΄νŠΈλ₯Ό μ–΄λ–»κ²Œ μ…‹νŒ…ν–ˆλŠ”μ§€(μœ„ λ‚΄μš© μ°Έκ³ )에 따라 μ•„λ§ˆμ‘΄μ— μ˜¬λ¦΄μ§€ Zip νŒŒμΌμ„ 생성할지λ₯Ό Defoldμ—κ²Œ μ•Œλ €μ€λ‹ˆλ‹€.

Packageλ₯Ό ν΄λ¦­ν•˜κ³  μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ λ²ˆλ“€μ΄ λ§Œλ“€μ–΄μ§ˆ μœ„μΉ˜λ₯Ό μ„ νƒν•©λ‹ˆλ‹€. 이제 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ‹œμž‘ν•΄μ„œ λͺ¨λ‘ μ˜ˆμƒλŒ€λ‘œ λ™μž‘ν•˜λŠ”μ§€ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

Setting up Amazon Web Service

μ•„λ§ˆμ‘΄ μ„œλΉ„μŠ€μ™€ Defold 라이브 μ—…λ°μ΄νŠΈ κΈ°λŠ₯을 ν•¨κ»˜ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ•„λ§ˆμ‘΄ μ›Ή μ„œλΉ„μŠ€ 계정이 ν•„μš”ν•©λ‹ˆλ‹€. 아직 계정이 μ€€λΉ„λ˜μ§€ μ•Šμ•˜λ‹€λ©΄ https://aws.amazon.com/ μ—μ„œ 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

이 μ„Ήμ…˜μ—μ„œλŠ” μ•„λ§ˆμ‘΄ μ›Ή μ„œλΉ„μŠ€μ—μ„œ μ œν•œλœ μ•‘μ„ΈμŠ€ κΆŒν•œμœΌλ‘œ μƒˆ μœ μ €λ₯Ό μƒμ„±ν•˜λŠ” 방법을 μ„€λͺ…ν•˜κ³ , κ²Œμž„ ν΄λΌμ΄μ–ΈνŠΈκ°€ μ•„λ§ˆμ‘΄ S3의 λ¦¬μ†ŒμŠ€λ₯Ό 탐색 ν•  수 μžˆλ„λ‘ μ„€μ •ν•˜λŠ” 방법도 ν•¨κ»˜ μ„€λͺ…ν•©λ‹ˆλ‹€. μ•„λ§ˆμ‘΄ S3 λ₯Ό μ„€μ •ν•˜λŠ” μžμ„Έν•œ μ •λ³΄λŠ” Amazon S3 λ¬Έμ„œλ₯Ό μ°Έκ³  λ°”λžλ‹ˆλ‹€.

1. Create a bucket for Live update resources

Services 메뉴λ₯Ό μ—΄κ³  Storage μΉ΄ν…Œκ³ λ¦¬(Amazon S3 Console)에 μžˆλŠ” S3λ₯Ό μ„ νƒν•©λ‹ˆλ‹€. κΈ°μ‘΄ 버켓(bucket)λ“€κ³Ό μƒˆ 버켓을 λ§Œλ“œλŠ” μ˜΅μ…˜μ„ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. κΈ°μ‘΄ 버켓을 μ‚¬μš©ν•  μˆ˜λ„ μžˆμ§€λ§Œ, μ•‘μ„ΈμŠ€ μ˜μ—­μ„ μ‰½κ²Œ μ œν•œν•  수 μžˆλ„λ‘ 라이브 μ—…λ°μ΄νŠΈ λ¦¬μ†ŒμŠ€(Live update resources)λ₯Ό μœ„ν•œ μƒˆ 버켓을 λ§Œλ“€κΈ° μΆ”μ²œν•©λ‹ˆλ‹€.

Create a bucket

2. Add a bucket policy to your bucket

μ‚¬μš©ν•˜λ €λŠ” 버켓을 μ„ νƒν•˜κ³  Properties νŒ¨λ„μ„ μ—΄μ–΄ νŒ¨λ„μ—μ„œ Permissions μ˜΅μ…˜μ„ ν™•μž₯ν•˜μ„Έμš”. Add bucket policy λ²„νŠΌμ„ ν΄λ¦­ν•΄μ„œ 버켓 정책을 μ—΄μ–΄λ³΄μ„Έμš”. 이 μƒ˜ν”Œμ˜ 버켓 정책은 아무 μœ μ €λ‚˜ λ²„μΌ“μ˜ νŒŒμΌλ“€μ„ 탐색할 수 있게 ν•΄μ£Όκ³ , κ²Œμž„ ν΄λΌμ΄μ–ΈνŠΈκ°€ 라이브 μ—…λ°μ΄νŠΈ λ¦¬μ†ŒμŠ€λ₯Ό λ‹€μš΄λ‘œλ“œ ν•  수 있게 ν•΄μ€λ‹ˆλ‹€. 버켓 정책에 λŒ€ν•œ 좔가정보λ₯Ό 보고 μ‹Άλ‹€λ©΄, Amazon λ¬Έμ„œλ₯Ό μ°Έκ³ ν•˜μ„Έμš”.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::defold-liveupdate-example/*"
        }
    ]
}

Bucket policy

3. Add a CORS configuration to your bucket (Optional)

Cross-Origin Resource Sharing (CORS)λŠ” JavsScriptλ₯Ό μ‚¬μš©ν•˜μ—¬ μ›Ήμ‚¬μ΄νŠΈμ—μ„œ μ„œλ‘œ λ‹€λ₯Έ λ„λ©”μΈμ˜ λ¦¬μ†ŒμŠ€λ₯Ό νƒμƒ‰ν•˜κ²Œ ν•΄ μ£ΌλŠ” λ©”μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€. λ§Œμ•½ λ‹Ήμ‹ μ˜ κ²Œμž„μ„ HTML5둜 λ°°ν¬ν•˜λ € ν•œλ‹€λ©΄, CORS 섀정을 λ‹Ήμ‹ μ˜ 버켓에 μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

μ‚¬μš©ν•˜λ €λŠ” 버켓을 μ„ νƒν•˜κ³  Properties νŒ¨λ„μ„ μ—΄μ–΄ νŒ¨λ„μ—μ„œ Permissions μ˜΅μ…˜μ„ ν™•μž₯ν•˜μ„Έμš”. Add CORS Configuration λ²„νŠΌμ„ ν΄λ¦­ν•΄μ„œ 버켓 정책을 μ—΄μ–΄λ³΄μ„Έμš”. μ•„λž˜ μƒ˜ν”Œμ˜ Configuration 은 μ™€μΌλ“œμΉ΄λ“œ(*) 도메인을 μ§€μ •ν•΄μ„œ μ–΄λ–€ μ›Ήμ‚¬μ΄νŠΈμ—μ„œλ“  μ•‘μ„ΈμŠ€λ˜κ²Œ ν•  수 μžˆμ§€λ§Œ, κ²Œμž„μ„ μ‹€ν–‰ν•  μ›Ήμ‚¬μ΄νŠΈμ˜ 도메인을 μ•Œκ³  μžˆλ‹€λ©΄ μ•‘μ„ΈμŠ€λ₯Ό μ œν•œν•˜λŠ” 것도 κ°€λŠ₯ν•©λ‹ˆλ‹€. Amazon CORS configuration 에 λŒ€ν•œ 더 λ§Žμ€ 정보λ₯Ό μ•Œκ³  μ‹Άλ‹€λ©΄ Amazon λ¬Έμ„œλ₯Ό μ°Έκ³  λ°”λžλ‹ˆλ‹€.

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
    </CORSRule>
</CORSConfiguration>

CORS configuration

4. Create IAM policy

Services 메뉴λ₯Ό μ—΄κ³  Security, Identity & Compliance μΉ΄ν…Œκ³ λ¦¬(Amazon IAM Console)에 μžˆλŠ” IAMλ₯Ό μ„ νƒν•©λ‹ˆλ‹€. μ™Όμͺ½μ— μžˆλŠ” λ©”λ‰΄μ—μ„œ Policiesλ₯Ό μ„ νƒν•˜λ©΄ κΈ°μ‘΄ μ •μ±…λ“€κ³Ό μƒˆ 정책을 λ§Œλ“œλŠ” μ˜΅μ…˜μ„ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

Create Policy λ²„νŠΌμ„ ν΄λ¦­ν•˜κ³  Create Your Own Policy λ₯Ό μ„ νƒν•˜μ„Έμš”. μ•„λž˜ 예제의 정책은 μœ μ €κ°€ Defold ν”„λ‘œμ νŠΈμ˜ 라이브 μ—…λ°μ΄νŠΈμ— μ„€μ •ν–ˆλ˜ λͺ¨λ“  λ²„μΌ“λ“€μ˜ λͺ©λ‘μ„ λ³Ό 수 있게 ν•΄μ€λ‹ˆλ‹€. λ˜ν•œ Access Control List (ACL)을 νšλ“ν•˜μ—¬ 라이브 μ—…λ°μ΄νŠΈ λ¦¬μ†ŒμŠ€μ— μ§€μ •λœ 버켓에 λ¦¬μ†ŒμŠ€λ₯Ό μ—…λ‘œλ“œ ν•  수 있게 ν•΄μ€λ‹ˆλ‹€. Amazon Identity 그리고 Access Management (IAM) 의 더 μžμ„Έν•œ 정보λ₯Ό μ•Œκ³  μ‹Άλ‹€λ©΄ Amazon λ¬Έμ„œλ₯Ό μ°Έκ³  λ°”λžλ‹ˆλ‹€.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketAcl"
            ],
            "Resource": "arn:aws:s3:::defold-liveupdate-example"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::defold-liveupdate-example/*"
        }
    ]
}

IAM policy

5. Create a user for programmatic access

Services 메뉴λ₯Ό μ—΄κ³  Security, Identity & Compliance μΉ΄ν…Œκ³ λ¦¬(Amazon IAM Console)에 μžˆλŠ” IAMλ₯Ό μ„ νƒν•©λ‹ˆλ‹€. μ™Όμͺ½μ— μžˆλŠ” λ©”λ‰΄μ—μ„œ Users λ₯Ό μ„ νƒν•˜λ©΄ κΈ°μ‘΄ μœ μ €λ“€κ³Ό μƒˆ μœ μ €λ₯Ό λ§Œλ“œλŠ” μ˜΅μ…˜μ„ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. κΈ°μ‘΄ μœ μ €λ₯Ό μ‚¬μš©ν•˜λŠ” 것도 μ’‹μ§€λ§Œ, μ•‘μ„ΈμŠ€ μ˜μ—­μ„ μ‰½κ²Œ μ œν•œν•  수 μžˆλ„λ‘ 라이브 μ—…λ°μ΄νŠΈ λ¦¬μ†ŒμŠ€(Live update resources)λ₯Ό μœ„ν•œ μƒˆ μœ μ €λ₯Ό λ§Œλ“€κΈ° μΆ”μ²œν•©λ‹ˆλ‹€.

Add User λ²„νŠΌμ„ ν΄λ¦­ν•˜κ³  username을 μ œκ³΅ν•˜κ³  Access type 으둜 Programmatic access λ₯Ό μ„ νƒν•©λ‹ˆλ‹€. 그리고 Next: Permissions λ₯Ό λˆŒλŸ¬μ„œ Attach existing policies directlyλ₯Ό μ„ νƒν•˜κ³  μœ„μ˜ 4. μ—μ„œ λ§Œλ“€μ—ˆλ˜ 정책을 μ„ νƒν•©λ‹ˆλ‹€.

이 μž‘μ—…μ„ μ™„λ €ν•˜λ©΄ Access key ID 와 Secret access key κ°€ μ œκ³΅λ©λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€μ—μ„œ λ‚˜κ°„ μ΄ν›„μ—λŠ” λ‹€μ‹œ μ•„λ§ˆμ‘΄μ—μ„œ 이 ν‚€λ₯Ό 쑰회 ν•  수 μ—†μœΌλ―€λ‘œ, 이듀 ν‚€λ₯Ό μ €μž₯ν•΄ λ‘λŠ” 것이 맀우 μ€‘μš”ν•©λ‹ˆλ‹€.

6. Create a credentials profile file

μ΄μ œκΉŒμ§€λŠ” 버켓을 λ§Œλ“€κ³ , 버켓 정책을 κ΅¬μ„±ν•˜κ³ , CORS 섀정을 μΆ”κ°€ν•˜κ³ , μƒˆ μœ μ €λ₯Ό μƒμ„±ν•˜κ³ , μœ μ € 정책을 생성 ν–ˆμŠ΅λ‹ˆλ‹€. 이제 남은 ν•œ κ°€μ§€λŠ” Defold 에디터가 μ‚¬μš©μžλ₯Ό λŒ€μ‹ ν•΄ 버켓에 μ•‘μ„ΈμŠ€ ν•  수 μžˆλ„λ‘ credentials profile νŒŒμΌμ„ μƒμ„±ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

λ‹Ήμ‹ μ˜ home 폴더에 ".aws" λΌλŠ” μƒˆ 디렉토리λ₯Ό μƒμ„±ν•˜κ³ , κ·Έ 폴더에 "credentials" νŒŒμΌμ„ μƒμ„±ν•˜μ„Έμš”.

$ mkdir ~/.aws
$ touch ~/.aws/credentials

"~/.aws/credentials" νŒŒμΌμ€ ν”„λ‘œκ·Έλž˜λ° λ°©μ‹μœΌλ‘œ AWS에 μ ‘κ·Όν•  수 있게 ν•΄μ£ΌλŠ” 자격증λͺ…이 ν¬ν•¨λ˜μ–΄ 있으며 μ΄λŠ” AWS credentials 을 κ΄€λ¦¬ν•˜λŠ” ν‘œμ€€ν™”λœ λ°©λ²•μž…λ‹ˆλ‹€. λ¬Έμ„œνŽΈμ§‘κΈ°λ‘œ 이 νŒŒμΌμ„ μ—΄μ–΄ λ‹Ήμ‹ μ˜ Access key ID 와 Secret access keyλ₯Ό μ•„λž˜ ν˜•μ‹μœΌλ‘œ μž…λ ₯ν•©λ‹ˆλ‹€.

[defold-liveupdate-example]
aws_access_key_id = <Access key ID>
aws_secret_access_key = <Secret access key>

이 defold-liveupdate-example μ˜ˆμ œμ—μ„œ <>κ΄„ν˜Έ μ•ˆμ— μ§€μ •ν•΄μ•Ό ν•˜λŠ” μ‹λ³„μžλŠ” Defold νŽΈμ§‘κΈ°μ—μ„œ ν”„λ‘œμ νŠΈμ˜ 라이브 μ—…λ°μ΄νŠΈ μ…‹νŒ…μ„ κ΅¬μ„±ν• λ•Œ μ œκ³΅ν–ˆλ˜ μ‹λ³„μžμ™€ λ™μΌν•©λ‹ˆλ‹€.

Live update settings

The manifest

λ©”λ‹ˆνŽ˜μŠ€νŠΈλŠ” 각 λ¦¬μ†ŒμŠ€μ˜ 해쉬값 뿐만 μ•„λ‹ˆλΌ λΉŒλ“œμ— ν¬ν•¨λœ λͺ¨λ“  λ¦¬μ†ŒμŠ€λ“€μ˜ λͺ©λ‘μ„ λ“€κ³  μžˆλŠ” λ‚΄λΆ€ 데이터 ꡬ쑰(internal data structure)μž…λ‹ˆλ‹€. 라이브 μ—…λ°μ΄νŠΈ κΈ°λŠ₯은 λ©”λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό μ‚¬μš©ν•˜μ—¬ λΉŒλ“œλœ κ²Œμž„μ˜ 파트λ₯Ό μΆ”μ²™ν•˜κ³ , λ‘œλ“œν•  수 μžˆλŠ” μ™ΈλΆ€ μ†ŒμŠ€λ₯Ό λ‚˜μ—΄ν•˜κ³ , λ‘œλ“œλœ 데이터가 μ†μƒλ˜μ§€ μ•Šμ•˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.

μœ μ € κ΄€μ μ—μ„œ λ©”λ‹ˆνŽ˜μŠ€νŠΈλŠ” 숫자 ν•Έλ“€(numeric handle)이며, 엔진을 κ΄€λ¦¬ν•˜λŠ” μ„ΈλΆ€ μ •λ³΄λŠ” 남겨 λ‘‘λ‹ˆλ‹€.

ν˜„μž¬λŠ” 초기 λΉŒλ“œ λ©”λ‹ˆνŽ˜μŠ€νŠΈ(initial build manifest)만 μ‚¬μš© κ°€λŠ₯ν•©λ‹ˆλ‹€. μƒˆ λ©”λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό μ €μž₯ν•˜λŠ” κΈ°λŠ₯은 μ‹œμŠ€ν…œμ— κ³„νšλœ μ—…λ°μ΄νŠΈ μ‚¬ν•­μž…λ‹ˆλ‹€. μ΄λŠ” μ•Œλ €μ§€μ§€ μ•Šμ€ μΆœν’ˆλœ κ²Œμž„μ˜ λ¦¬μ†ŒμŠ€λ₯Ό λΉŒλ“œ νƒ€μž„μ— μˆ˜μ •ν•˜κ±°λ‚˜ μΆ”κ°€ν•  수 있게 ν•΄ μ€λ‹ˆλ‹€.

Development caveats

Debugging

κ²Œμž„μ„ λ²ˆλ“€ λ²„μ „μœΌλ‘œ μ‹€ν–‰ν•˜λ©΄, μ½˜μ†”μ— 직접 μ•‘μ„ΈμŠ€ ν•  수 μ—†κ²Œ λ˜μ–΄ 디버깅에 λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ, μ»€λ§¨λ“œ 라인 ν˜Ήμ€ λ²ˆλ“€ λ””λ ‰ν† λ¦¬μ˜ μ‹€ν–‰νŒŒμΌμ„ 직접 λ”λΈ”ν΄λ¦­ν•΄μ„œ μ–΄λΈ”λ¦¬μΌ€μ΄μ…˜μ„ μ‹€ν–‰ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Running a bundle application

이제 κ²Œμž„μ΄ μ‹œμž‘λ˜κ³  μ‰˜ μœˆλ„μš°μ— print() 문을 좜λ ₯ν•˜κ²Œ λ©λ‹ˆλ‹€.

Console output

Forcing re-download of resources

μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ¦¬μ†ŒμŠ€λ₯Ό μ €μž₯ν•˜λ € ν•˜λ©΄, 둜컬 μ»΄ν“¨ν„°λ‚˜ νœ΄λŒ€μž₯치의 λ””μŠ€ν¬μ— μ €μž₯λ©λ‹ˆλ‹€. λ§Œμ•½ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μž¬μ‹œμž‘ν•΄λ„, 이 λ¦¬μ†ŒμŠ€λ“€μ€ μ—¬μ „νžˆ κ·ΈλŒ€λ‘œ μžˆμŠ΅λ‹ˆλ‹€. κ°œλ°œμ€‘μΈ κ²½μš°λŠ” λ•Œλ‘œ λ¦¬μ†ŒμŠ€λ“€μ„ μ‚­μ œν•΄μ•Όν•  κ²½μš°λ„ 있고 κ°•μ œλ‘œ λ‹€μ‹œ λ‹€μš΄λ‘œλ“œ ν•΄μ•Όν•  κ²½μš°λ„ μžˆμŠ΅λ‹ˆλ‹€. sys.get_save_file() ν•¨μˆ˜λŠ” Defoldκ°€ λ¦¬μ†ŒμŠ€λ₯Ό μ €μž₯ν•˜λŠ” 경둜λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. μ € ν΄λ”μ—μ„œ, DefoldλŠ” μƒμ„±λœ λ²ˆλ“€μ˜ 해쉬 이름을 μ‚¬μš©ν•˜μ—¬ 폴더λ₯Ό λ§Œλ“­λ‹ˆλ‹€. λ§Œμ•½ 이 ν΄λ”μ˜ νŒŒμΌλ“€μ„ μ‚­μ œν•˜λ©΄, μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λ©”λ‹ˆνŽ˜μŠ€νŠΈμ˜ λ¦¬μ†ŒμŠ€λ₯Ό 무효처리(invalidate) ν•˜λ―€λ‘œ 당신은 이λ₯Ό λ‹€μ‹œ λ‹€μš΄λ‘œλ“œν•˜κ³  μ €μž₯ν•  수 있게 λ©λ‹ˆλ‹€.

Local storage

Known issues

  • ν˜„μž¬λŠ” λΉŒλ“œνƒ€μž„μ— μƒμ„±ν•œ λ©”λ‹ˆνŽ˜μŠ€νŠΈλ§Œ μ•‘μ„ΈμŠ€ν•  수 μžˆμŠ΅λ‹ˆλ‹€. κ°€κΉŒμš΄ μ‹œμΌ 내에 μƒˆ λ©”λ‹ˆνŽ˜μŠ€νŠΈλ₯Ό μ €μž₯ν•˜λ„λ‘ ν•  μ˜ˆμ •μž…λ‹ˆλ‹€. μ΄λŠ” κΈ°μ‘΄ λ¦¬μ†ŒμŠ€λ₯Ό μˆ˜μ •ν•˜κ±°λ‚˜ 라이브 μ—…λ°μ΄νŠΈλ₯Ό 톡해 μƒˆ λ¦¬μ†ŒμŠ€λ₯Ό κ²Œμž„μ— μΆ”κ°€ν•  수 있게 ν•΄ μ€λ‹ˆλ‹€.

  • ν˜„μž¬ resource.store_resource() λŠ” 메인 μŠ€λ ˆλ“œλ₯Ό 차단(block)ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 즉, 큰 λ¦¬μ†ŒμŠ€λ₯Ό μ €μž₯ν•˜λ©΄ λŠκΉ€ ν˜„μƒμ΄ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

⚠️ **GitHub.com Fallback** ⚠️