1"use strict";(globalThis.webpackChunkbambuser_docs||=[]).push([[4756],{12037(e,r,n){n.r(r),n.d(r,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>a});const i=JSON.parse('{"id":"mobileSDK/ios/sv-ios-delegate-protocol","title":"Delegate Protocol","description":"BambuserVideoPlayerDelegate for Shoppable Video iOS: all 5 callback methods, BambuserVideoState table, error handling pattern, onVideoProgress and onThumbnailTapped.","source":"@site/shoppable-video/mobileSDK/ios/delegate-protocol.mdx","sourceDirName":"mobileSDK/ios","slug":"/mobileSDK/ios/mobile-sdk/ios/delegate-protocol","permalink":"/docs/shoppable-video/mobileSDK/ios/mobile-sdk/ios/delegate-protocol","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"id":"sv-ios-delegate-protocol","title":"Delegate Protocol","description":"BambuserVideoPlayerDelegate for Shoppable Video iOS: all 5 callback methods, BambuserVideoState table, error handling pattern, onVideoProgress and onThumbnailTapped.","sidebar_label":"Delegate Protocol","slug":"mobile-sdk/ios/delegate-protocol"},"sidebar":"someSidebars","previous":{"title":"Setup","permalink":"/docs/shoppable-video/mobileSDK/ios/mobile-sdk/ios/setup"},"next":{"title":"Configuration and Functions","permalink":"/docs/shoppable-video/mobileSDK/ios/mobile-sdk/ios/configuration-and-functions"}}');var d=n(74848),t=n(28453);const o={id:"sv-ios-delegate-protocol",title:"Delegate Protocol",description:"BambuserVideoPlayerDelegate for Shoppable Video iOS: all 5 callback methods, BambuserVideoState table, error handling pattern, onVideoProgress and onThumbnailTapped.",sidebar_label:"Delegate Protocol",slug:"mobile-sdk/ios/delegate-protocol"},s="Delegate Protocol",l={},a=[{value:"Protocol Methods",id:"protocol-methods",level:2},{value:"<code>onVideoStatusChanged(_:state:)</code> \u2014 required",id:"onvideostatuschanged_state--required",level:3},{value:"<code>onNewEventReceived(_:event:)</code> \u2014 required",id:"onneweventreceived_event--required",level:3},{value:"<code>onErrorOccurred(_:error:)</code> \u2014 required",id:"onerroroccurred_error--required",level:3},{value:"<code>onVideoProgress(_:duration:currentTime:)</code> \u2014 optional",id:"onvideoprogress_durationcurrenttime--optional",level:3},{value:"<code>onThumbnailTapped(_:)</code> \u2014 optional",id:"onthumbnailtapped_--optional",level:3},{value:"Full Example Implementation",id:"full-example-implementation",level:2},{value:"BambuserVideoState Reference",id:"bambuservideostate-reference",level:2},{value:"Error Handling Pattern",id:"error-handling-pattern",level:2},{value:"Next Steps",id:"next-steps",level:2}];function c(e){const r={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(r.header,{children:(0,d.jsx)(r.h1,{id:"delegate-protocol",children:"Delegate Protocol"})}),"\n",(0,d.jsxs)(r.p,{children:[(0,d.jsx)(r.code,{children:"BambuserVideoPlayerDelegate"})," is the protocol your class implements to receive callbacks from a ",(0,d.jsx)(r.code,{children:"BambuserPlayerView"}),". Assign your conforming object to ",(0,d.jsx)(r.code,{children:"playerView.delegate"})," after creating the player."]}),"\n",(0,d.jsx)(r.h2,{id:"protocol-methods",children:"Protocol Methods"}),"\n",(0,d.jsxs)(r.h3,{id:"onvideostatuschanged_state--required",children:[(0,d.jsx)(r.code,{children:"onVideoStatusChanged(_:state:)"})," \u2014 required"]}),"\n",(0,d.jsx)(r.p,{children:"Called whenever the playback state of the player changes."}),"\n",(0,d.jsxs)(r.table,{children:[(0,d.jsx)(r.thead,{children:(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.th,{children:"Parameter"}),(0,d.jsx)(r.th,{children:"Type"}),(0,d.jsx)(r.th,{children:"Description"})]})}),(0,d.jsxs)(r.tbody,{children:[(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"id"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"String"})}),(0,d.jsx)(r.td,{children:"The unique identifier of the player instance"})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"state"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"BambuserVideoState"})}),(0,d.jsx)(r.td,{children:"The new playback state"})]})]})]}),"\n",(0,d.jsxs)(r.h3,{id:"onneweventreceived_event--required",children:[(0,d.jsx)(r.code,{children:"onNewEventReceived(_:event:)"})," \u2014 required"]}),"\n",(0,d.jsx)(r.p,{children:"Called when the player emits a business-logic event such as cart actions, product interactions, or navigation requests."}),"\n",(0,d.jsxs)(r.table,{children:[(0,d.jsx)(r.thead,{children:(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.th,{children:"Parameter"}),(0,d.jsx)(r.th,{children:"Type"}),(0,d.jsx)(r.th,{children:"Description"})]})}),(0,d.jsxs)(r.tbody,{children:[(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"id"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"String"})}),(0,d.jsx)(r.td,{children:"The unique identifier of the player instance"})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"event"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"BambuserEventPayload"})}),(0,d.jsx)(r.td,{children:"Event type string and associated data dictionary"})]})]})]}),"\n",(0,d.jsxs)(r.h3,{id:"onerroroccurred_error--required",children:[(0,d.jsx)(r.code,{children:"onErrorOccurred(_:error:)"})," \u2014 required"]}),"\n",(0,d.jsx)(r.p,{children:"Called when an unrecoverable error occurs inside the player."}),"\n",(0,d.jsxs)(r.table,{children:[(0,d.jsx)(r.thead,{children:(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.th,{children:"Parameter"}),(0,d.jsx)(r.th,{children:"Type"}),(0,d.jsx)(r.th,{children:"Description"})]})}),(0,d.jsxs)(r.tbody,{children:[(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"id"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"String"})}),(0,d.jsx)(r.td,{children:"The unique identifier of the player instance"})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"error"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"Error"})}),(0,d.jsx)(r.td,{children:"The underlying error"})]})]})]}),"\n",(0,d.jsxs)(r.h3,{id:"onvideoprogress_durationcurrenttime--optional",children:[(0,d.jsx)(r.code,{children:"onVideoProgress(_:duration:currentTime:)"})," \u2014 optional"]}),"\n",(0,d.jsx)(r.p,{children:"Called periodically during playback to report progress. Use this for custom progress indicators or analytics."}),"\n",(0,d.jsxs)(r.table,{children:[(0,d.jsx)(r.thead,{children:(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.th,{children:"Parameter"}),(0,d.jsx)(r.th,{children:"Type"}),(0,d.jsx)(r.th,{children:"Description"})]})}),(0,d.jsxs)(r.tbody,{children:[(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"id"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"String"})}),(0,d.jsx)(r.td,{children:"The unique identifier of the player instance"})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"duration"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"Double"})}),(0,d.jsx)(r.td,{children:"Total duration of the video in seconds"})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"currentTime"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"Double"})}),(0,d.jsx)(r.td,{children:"Current playback position in seconds"})]})]})]}),"\n",(0,d.jsxs)(r.h3,{id:"onthumbnailtapped_--optional",children:[(0,d.jsx)(r.code,{children:"onThumbnailTapped(_:)"})," \u2014 optional"]}),"\n",(0,d.jsx)(r.p,{children:"Called when the user taps the video thumbnail before playback begins. Use this to trigger custom pre-play behaviour such as a loading overlay or analytics event."}),"\n",(0,d.jsxs)(r.table,{children:[(0,d.jsx)(r.thead,{children:(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.th,{children:"Parameter"}),(0,d.jsx)(r.th,{children:"Type"}),(0,d.jsx)(r.th,{children:"Description"})]})}),(0,d.jsx)(r.tbody,{children:(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"id"})}),(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:"String"})}),(0,d.jsx)(r.td,{children:"The unique identifier of the player instance"})]})})]}),"\n",(0,d.jsx)(r.h2,{id:"full-example-implementation",children:"Full Example Implementation"}),"\n",(0,d.jsx)(r.pre,{children:(0,d.jsx)(r.code,{className:"language-swift",metastring:'title="VideoFeedViewController.swift"',children:'extension VideoFeedViewController: BambuserVideoPlayerDelegate {\n\n func onVideoStatusChanged(_ id: String, state: BambuserVideoState) {\n switch state {\n case .loading:\n print("Player \\(id) is loading")\n case .playing:\n print("Player \\(id) is playing")\n case .paused:\n print("Player \\(id) is paused")\n case .completed:\n print("Player \\(id) finished \u2014 advance to next video")\n advanceToNextVideo()\n case .error:\n DispatchQueue.main.async {\n self.removePlayer(id: id)\n self.showErrorBanner("This video is unavailable.")\n }\n }\n }\n\n func onNewEventReceived(_ id: String, event: BambuserEventPayload) {\n switch event.type {\n case "should-add-item-to-cart":\n handleAddToCart(id: id, event: event)\n case "provide-product-data":\n Task { try await hydrate(id: id, data: event.data) }\n default:\n break\n }\n }\n\n func onErrorOccurred(_ id: String, error: Error) {\n // Log to your crash reporting service\n print("Player \\(id) error: \\(error.localizedDescription)")\n }\n\n func onVideoProgress(_ id: String, duration: Double, currentTime: Double) {\n let progress = duration > 0 ? currentTime / duration : 0\n updateProgressBar(for: id, progress: progress)\n }\n\n func onThumbnailTapped(_ id: String) {\n // Optional: show a loading overlay before play() fires\n showLoadingOverlay(for: id)\n }\n}\n'})}),"\n",(0,d.jsx)(r.h2,{id:"bambuservideostate-reference",children:"BambuserVideoState Reference"}),"\n",(0,d.jsxs)(r.table,{children:[(0,d.jsx)(r.thead,{children:(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.th,{children:"State"}),(0,d.jsx)(r.th,{children:"When it fires"})]})}),(0,d.jsxs)(r.tbody,{children:[(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:".loading"})}),(0,d.jsx)(r.td,{children:"Player is initialising or buffering"})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:".playing"})}),(0,d.jsxs)(r.td,{children:["Playback is active after ",(0,d.jsx)(r.code,{children:"play()"})," or autoplay"]})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:".paused"})}),(0,d.jsxs)(r.td,{children:["Playback was paused via ",(0,d.jsx)(r.code,{children:"pause()"})," or by the user"]})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:".completed"})}),(0,d.jsx)(r.td,{children:"The video played to the end"})]}),(0,d.jsxs)(r.tr,{children:[(0,d.jsx)(r.td,{children:(0,d.jsx)(r.code,{children:".error"})}),(0,d.jsx)(r.td,{children:"An unrecoverable error occurred (e.g., invalid video ID, network failure)"})]})]})]}),"\n",(0,d.jsx)(r.admonition,{type:"note",children:(0,d.jsxs)(r.p,{children:["Read the current state at any time via ",(0,d.jsx)(r.code,{children:"playerView.currentPlayerState"})," without waiting for a callback."]})}),"\n",(0,d.jsx)(r.h2,{id:"error-handling-pattern",children:"Error Handling Pattern"}),"\n",(0,d.jsxs)(r.p,{children:["When the player enters the ",(0,d.jsx)(r.code,{children:".error"})," state, two callbacks fire in sequence:"]}),"\n",(0,d.jsxs)(r.ol,{children:["\n",(0,d.jsxs)(r.li,{children:[(0,d.jsx)(r.code,{children:"onVideoStatusChanged"})," with ",(0,d.jsx)(r.code,{children:"state: .error"})]}),"\n",(0,d.jsxs)(r.li,{children:[(0,d.jsx)(r.code,{children:"onErrorOccurred"})," with the underlying ",(0,d.jsx)(r.code,{children:"Error"})]}),"\n"]}),"\n",(0,d.jsxs)(r.p,{children:["Use ",(0,d.jsx)(r.code,{children:"onVideoStatusChanged"})," to update the UI and ",(0,d.jsx)(r.code,{children:"onErrorOccurred"})," to log or report the error:"]}),"\n",(0,d.jsx)(r.pre,{children:(0,d.jsx)(r.code,{className:"language-swift",metastring:'title="VideoFeedViewController.swift"',children:'func onVideoStatusChanged(_ id: String, state: BambuserVideoState) {\n guard state == .error else { return }\n DispatchQueue.main.async {\n // Remove the broken player from your feed\n self.playerContainers[id]?.removeFromSuperview()\n }\n}\n\nfunc onErrorOccurred(_ id: String, error: Error) {\n // Forward to your telemetry/crash reporting\n Analytics.record(error: error, context: ["playerId": id])\n}\n'})}),"\n",(0,d.jsx)(r.p,{children:(0,d.jsx)(r.strong,{children:"Common error causes:"})}),"\n",(0,d.jsxs)(r.ul,{children:["\n",(0,d.jsx)(r.li,{children:"Invalid, deleted, or unpublished video ID"}),"\n",(0,d.jsx)(r.li,{children:"Network failure during player initialisation"}),"\n",(0,d.jsx)(r.li,{children:"Unsupported video format"}),"\n"]}),"\n",(0,d.jsx)(r.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,d.jsxs)(r.ul,{children:["\n",(0,d.jsxs)(r.li,{children:[(0,d.jsx)(r.a,{href:"/docs/shoppable-video/mobileSDK/ios/mobile-sdk/ios/cart-integration",children:"Cart Integration"})," \u2014 handle ",(0,d.jsx)(r.code,{children:"should-add-item-to-cart"})," inside ",(0,d.jsx)(r.code,{children:"onNewEventReceived"}),"."]}),"\n",(0,d.jsxs)(r.li,{children:[(0,d.jsx)(r.a,{href:"/docs/shoppable-video/mobileSDK/ios/mobile-sdk/ios/product-hydration",children:"Product Hydration"})," \u2014 respond to ",(0,d.jsx)(r.code,{children:"provide-product-data"})," events."]}),"\n",(0,d.jsxs)(r.li,{children:[(0,d.jsx)(r.a,{href:"/docs/shoppable-video/mobileSDK/ios/mobile-sdk/ios/tracking",children:"Tracking"})," \u2014 send conversion events after purchases."]}),"\n"]})]})}function h(e={}){const{wrapper:r}={...(0,t.R)(),...e.components};return r?(0,d.jsx)(r,{...e,children:(0,d.jsx)(c,{...e})}):c(e)}},28453(e,r,n){n.d(r,{R:()=>o,x:()=>s});var i=n(96540);const d={},t=i.createContext(d);function o(e){const r=i.useContext(t);return i.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function s(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:o(e.components),i.createElement(t.Provider,{value:r},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.