์น์ฑ ์ฐ๋
React Native ์น์ฑ ์ฐ๋์ ์ํด์ ์๋์ ์์ ์ด ํ์ํฉ๋๋ค.
- React Native SDK์์ WebView๋ฅผ ๋ ๋๋งํ๋ ์์ ์ ๋ธ๋ฆฟ์ง๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- WebView์์ ์ฌ์ฉํ๋ JavaScript SDK๋ฅผ ๋ํํ์ฌ ReactNative ์ ์ฉ Client๋ฅผ ์์ฑํด์ผํฉ๋๋ค.
์น์ฑ์ ๋ํด์๋ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
WebView
๋ฅผ ํตํด ์์ฌ ์น์ฌ์ดํธ๋ฅผ ๋๋๋งํ๋ ๊ฒฝ์ฐ, ์๋ ์ค์ ์ ํตํด ์น์ฌ์ดํธ์ ํฌํจ๋ ํตํด JavaScript SDK๋ฅผ ์น์ฌ์ดํธ ์ฝ๋ ๋ณ๊ฒฝ์์ด ํตํด React Native SDK ๊ธฐ๋ฅ๊ณผ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
React Native
React Native SDK๊ฐ ์ค์น๋ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์์ ์๋ ์์ ์ ์งํํด์ฃผ์ธ์.
Github: Source
- ์ ์์ค ์ฝ๋์
useHackleWebviewManager
๋ฅผ ํ๋ก์ ํธ์ ์ถ๊ฐํฉ๋๋ค. useHackleWebviewManager
hook์ ํตํด WebView์ prop์ ์ ๋ฌํฉ๋๋ค.
ReactNative WebView JS Injection
๊ตฌ๋ถ | ์ค๋ช |
---|---|
hackleInjectedJavaScript | ์น๋ทฐ์ JavaScript SDK๊ฐ React Native SDK์๊ฒ ๊ธฐ๋ฅ์ ๋์ ์ฒ๋ฆฌํ๋๋ก ๋ฉ์ธ์ง๋ฅผ ์ ๋ฌํฉ๋๋ค. |
onHackleMessage | javaScript SDK๋ก ๋ถํฐ ์ ๋ฌ๋ฐ์ ๋ฉ์ธ์ง๋ฅผ React Native SDK์์ ์ฒ๋ฆฌํฉ๋๋ค. |
const hackleClient = createInstance("YOUR_SDK_KEY");
function App() {
const webviewRef = useRef(null);
const { hackleInjectedJavaScript, onHackleMessage, isHackleMessageEvent } =
useHackleWebviewManager({
postMessage: (message) => webviewRef.current?.postMessage(message),
hackleClient,
});
return (
<HackleProvider hackleClient={hackleClient}>
<SafeAreaView>
<View>
<WebView
ref={webviewRef}
source={{ uri: "web_url" }}
injectedJavaScriptBeforeContentLoaded={hackleInjectedJavaScript}
onMessage={(e) => {
if (isHackleMessageEvent(e)) {
onHackleMessage(e.nativeEvent.data);
return;
}
}}
/>
</View>
</SafeAreaView>
</HackleProvider>
);
}
JavaScript
JavaScript SDK๊ฐ ์ค์น ๋ ์น ์ฌ์ด๋์์ ์๋ ์์ ์ ์งํํด์ฃผ์ธ์.
JavaScript ๋ธ๋ฆฟ์ง ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ ๋์์ ํฉ๋๋ค.
- JavaScript SDK์ hackleClient์ ๋์ผํ ์ธํฐํ์ด์ค๋ฅผ ๊ฐ๋ Wrapper Client๋ฅผ ์์ฑํฉ๋๋ค.
- Web ํ๊ฒฝ์์ ๋ฐ์ํ๋ track, variation, featureFlag ๋ฑ์ ์์ฒญ์ ๋ฐ์์ React Native SDK๋ก ๋น๋๊ธฐ ์ ๋ฌํฉ๋๋ค.
- ์ด๋ฅผ ์ํ ๋ธ๋ฆฟ์ง ํํ์ ์ฝ๋์ด๊ณ , ๋ชจ๋ ๋ฉ์๋๊ฐ Promise๋ฅผ ๋ฐํํ๋ค๋ ์ ์ด ๊ธฐ์กด hackleClient์์ ์ฐจ์ด์ ๋๋ค.
React Native์์ ๋ธ๋ฆฟ์ง ์์ ์ด ์ ํ๋์ด์ผํฉ๋๋ค.
- ReactNative WebView์
useHackleWebviewManager
๋ฅผ ์ ์ฉํด์ผํฉ๋๋ค.- ์ ์์ ์ด ์ ํ๋์ง ์์ ๊ฒฝ์ฐ ์น์ฑ ์ฐ๋์ด ์ ์์ ์ผ๋ก ์ด๋ฃจ์ด์ง์ง ์์ต๋๋ค.
Github: Full Source Code
import{createInstance as e,Decision as t,DecisionReason as r,FeatureFlagDecision as n}from"@hackler/javascript-sdk";import{v4 as o}from"uuid";var s=function(e,t){return s=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},s(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function r(){this.constructor=e}s(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function u(e,t,r,n){return new(r||(r=Promise))(function(o,s){function i(e){try{c(n.next(e))}catch(e){s(e)}}function u(e){try{c(n.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r(function(e){e(t)})).then(i,u)}c((n=n.apply(e,t||[])).next())})}function c(e,t){var r,n,o,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return i.next=u(0),i.throw=u(1),i.return=u(2),"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function u(u){return function(c){return function(u){if(r)throw new TypeError("Generator is already executing.");for(;i&&(i=0,u[0]&&(s=0)),s;)try{if(r=1,n&&(o=2&u[0]?n.return:u[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,u[1])).done)return o;switch(n=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return s.label++,{value:u[1],done:!1};case 5:s.label++,n=u[1],u=[0];continue;case 7:u=s.ops.pop(),s.trys.pop();continue;default:if(!(o=s.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){s=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){s.label=u[1];break}if(6===u[0]&&s.label<o[1]){s.label=o[1],o=u;break}if(o&&s.label<o[2]){s.label=o[2],s.ops.push(u);break}o[2]&&s.ops.pop(),s.trys.pop();continue}u=t.call(e,s)}catch(e){u=[6,e],n=0}finally{r=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,c])}}}"function"==typeof SuppressedError&&SuppressedError;var a=function(){function e(){this.listeners={}}return e.prototype.on=function(e,t){this.listeners[e]=(this.listeners[e]||[]).concat(t)},e.prototype.off=function(e,t){this.listeners[e]=(this.listeners[e]||[]).filter(function(e){return e!==t})},e.prototype.emit=function(e,t){(this.listeners[e]||[]).forEach(function(e){e(t)})},e}(),p=function(){function e(e){this.parameters=e,this.parameters=e}return e.prototype.get=function(e,t){var r=this.parameters[e];return null==r?t:null==t||typeof r==typeof t?r:t},e}(),f=function(){function e(e){this.configFetcher=e,this.configFetcher=e}return e.prototype.get=function(e,t){return u(this,void 0,void 0,function(){var r,n,o;return c(this,function(s){switch(s.label){case 0:return s.trys.push([0,2,,3]),[4,this.configFetcher(e,t)];case 1:if(!(r=s.sent()))throw new Error("invoke result data not exists");switch(n=r.configValue,typeof t){case"number":return[2,Number(n)];case"boolean":return[2,Boolean(n)];default:return[2,n]}case 2:return o=s.sent(),console.error("Unexpected exception while deciding remote config parameter[".concat(e,"]. Returning default value. : ").concat(o)),[2,t];case 3:return[2]}})})},e}();function l(e,t){var r=t.timeoutMillis,n=void 0===r?5e3:r,o=t.onTimeout;return new Promise(function(t,r){e(t,r),setTimeout(function(){o(t,r)},n)})}var d=function(){function e(){this.injectFlag="_hackle_injected"}return e.prototype.isInjectedEnvironment=function(){return!("undefined"==typeof window||!window.ReactNativeWebView)&&!0===window[this.injectFlag]},e.prototype.createInstance=function(e,t){if(this.isInjectedEnvironment()){var r=new h(window.ReactNativeWebView);return new v(e,t,r)}return new m(e,t)},e}(),h=function(){function e(e){this.port=e,this.cleanUp=function(){}}return e.prototype.addEventListener=function(e){window.addEventListener("message",e,!0),this.cleanUp=function(){return window.removeEventListener("message",e,!0)}},e}(),v=function(e){function s(t,r,n){var o=e.call(this)||this;return o.sdkKey=t,o.config=r,o.messageTransceiver=n,o.messageFieldName="_hackle_message",o.resolverRecord=new Map,o.messageTransceiver.addEventListener(function(e){var t,r=e;if(r.data&&"undefined"!==r.data)try{var n=JSON.parse(r.data);if(o.messageFieldName in n){var s=n[o.messageFieldName],i=s.id,u=s.payload;i&&(null===(t=o.resolverRecord.get(i))||void 0===t||t(u),o.resolverRecord.delete(i))}}catch(e){console.log("[DEBUG] Hackle: Failed to parse message. If message not sent by hackle, please ignore this. ".concat(e))}}),o}return i(s,e),s.prototype.onInitialized=function(e){return Promise.resolve({success:!0})},s.prototype.createMessage=function(e,t,r){var n;return JSON.stringify(((n={})[this.messageFieldName]={id:e,type:t,payload:r},n))},s.prototype.createId=function(){return o()},s.prototype.getSessionId=function(){return u(this,void 0,void 0,function(){var e,t=this;return c(this,function(r){switch(r.label){case 0:return e=this.createId(),[4,l(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"getSessionId",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e({sessionId:""})}})];case 1:return[2,r.sent().sessionId]}})})},s.prototype.getUser=function(){return u(this,void 0,void 0,function(){var e,t=this;return c(this,function(r){switch(r.label){case 0:return e=this.createId(),[4,l(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"getUser",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e({user:{}})}})];case 1:return[2,r.sent().user]}})})},s.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},s.prototype.setUser=function(e){return u(this,void 0,void 0,function(){var t,r=this;return c(this,function(n){return t=this.createId(),[2,l(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setUser",{user:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.setUserId=function(e){return u(this,void 0,void 0,function(){var t,r=this;return c(this,function(n){return t=this.createId(),[2,l(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setUserId",{userId:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.setDeviceId=function(e){return u(this,void 0,void 0,function(){var t,r=this;return c(this,function(n){return t=this.createId(),[2,l(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setDeviceId",{deviceId:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.setUserProperty=function(e,t){return u(this,void 0,void 0,function(){var r,n=this;return c(this,function(o){return r=this.createId(),[2,l(function(o){n.messageTransceiver.port.postMessage(n.createMessage(r,"setUserProperty",{key:e,value:t})),n.resolverRecord.set(r,o)},{onTimeout:function(e){return e()}}).then(function(){n.emitUserUpdated()})]})})},s.prototype.setUserProperties=function(e){return u(this,void 0,void 0,function(){var t,r=this;return c(this,function(n){return t=this.createId(),[2,l(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setUserProperties",{properties:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.updateUserProperties=function(e){return u(this,void 0,void 0,function(){var t,r=this;return c(this,function(n){return t=this.createId(),[2,l(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"updateUserProperties",{operations:e.toRecord()})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.updatePushSubscriptions=function(e){var t=this,r=this.createId();return l(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"updatePushSubscriptions",{operations:e.toRecord()})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.updateSmsSubscriptions=function(e){var t=this,r=this.createId();return l(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"updateSmsSubscriptions",{operations:e.toRecord()})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.updateKakaoSubscriptions=function(e){var t=this,r=this.createId();return l(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"updateKakaoSubscriptions",{operations:e.toRecord()})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.setPhoneNumber=function(e){var t=this,r=this.createId();return l(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"setPhoneNumber",{phoneNumber:e})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.unsetPhoneNumber=function(){var e=this,t=this.createId();return l(function(r){e.messageTransceiver.port.postMessage(e.createMessage(t,"unsetPhoneNumber",null)),e.resolverRecord.set(t,r)},{onTimeout:function(e){return e()}})},s.prototype.resetUser=function(){return u(this,void 0,void 0,function(){var e,t=this;return c(this,function(r){return e=this.createId(),[2,l(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"resetUser",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e()}}).then(function(){t.emitUserUpdated()})]})})},s.prototype.variation=function(e){return u(this,void 0,void 0,function(){var t,r=this;return c(this,function(n){switch(n.label){case 0:return t=this.createId(),[4,l(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"variation",{experimentKey:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e({variation:"A"})}})];case 1:return[2,n.sent().variation]}})})},s.prototype.variationDetail=function(e){return u(this,void 0,void 0,function(){var n,o,s,i,u,a=this;return c(this,function(c){switch(c.label){case 0:n=this.createId(),c.label=1;case 1:return c.trys.push([1,3,,4]),[4,l(function(t){a.messageTransceiver.port.postMessage(a.createMessage(n,"variationDetail",{experimentKey:e})),a.resolverRecord.set(n,t)},{onTimeout:function(e,t){return t()}})];case 2:return o=c.sent(),s=o.variation,i=o.reason,u=o.parameters,[2,t.of(s,i,new p(null!=u?u:{}))];case 3:return c.sent(),[2,t.of("A",r.EXCEPTION)];case 4:return[2]}})})},s.prototype.isFeatureOn=function(e){return u(this,void 0,void 0,function(){var t,r=this;return c(this,function(n){switch(n.label){case 0:return t=this.createId(),[4,l(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"isFeatureOn",{featureKey:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e({isOn:!1})}})];case 1:return[2,n.sent().isOn]}})})},s.prototype.featureFlagDetail=function(e){return u(this,void 0,void 0,function(){var t,o,s,i,u,a=this;return c(this,function(c){switch(c.label){case 0:t=this.createId(),c.label=1;case 1:return c.trys.push([1,3,,4]),[4,l(function(r){a.messageTransceiver.port.postMessage(a.createMessage(t,"featureFlagDetail",{featureKey:e})),a.resolverRecord.set(t,r)},{onTimeout:function(e,t){return t()}})];case 2:return o=c.sent(),s=o.isOn,i=o.reason,u=o.parameters,[2,new n(s,i,new p(null!=u?u:{}),void 0)];case 3:return c.sent(),[2,n.off(r.EXCEPTION)];case 4:return[2]}})})},s.prototype.track=function(e){var t=this,r=this.createId();return l(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"track",{event:e})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.trackPageView=function(){return u(this,void 0,void 0,function(){return c(this,function(e){return[2]})})},s.prototype.remoteConfig=function(){var e=this;return new f(function(t,r){var n=e.createId();return l(function(o){e.messageTransceiver.port.postMessage(e.createMessage(n,"remoteConfig",{key:t,defaultValue:r})),e.resolverRecord.set(n,o)},{onTimeout:function(e){return e(r)}})})},s.prototype.showUserExplorer=function(){var e=this,t=this.createId();return l(function(r){e.messageTransceiver.port.postMessage(e.createMessage(t,"showUserExplorer",null)),e.resolverRecord.set(t,r)},{onTimeout:function(e){return e()}})},s.prototype.hideUserExplorer=function(){return u(this,void 0,void 0,function(){var e,t=this;return c(this,function(r){return e=this.createId(),[2,l(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"hideUserExplorer",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e()}})]})})},s.prototype.fetch=function(){var e=this,t=this.createId();return l(function(r){e.messageTransceiver.port.postMessage(e.createMessage(t,"fetch",null)),e.resolverRecord.set(t,r)},{onTimeout:function(e){return e()}})},s}(a),m=function(t){function r(r,n){var o=t.call(this)||this;return o.client=e(r,n),o}return i(r,t),r.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},r.prototype.getSessionId=function(){return Promise.resolve(this.client.getSessionId())},r.prototype.getUser=function(){return Promise.resolve(this.client.getUser())},r.prototype.setUser=function(e){return u(this,void 0,void 0,function(){var t=this;return c(this,function(r){return[2,Promise.resolve(this.client.setUser(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserId=function(e){return u(this,void 0,void 0,function(){var t=this;return c(this,function(r){return[2,Promise.resolve(this.client.setUserId(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setDeviceId=function(e){return u(this,void 0,void 0,function(){var t=this;return c(this,function(r){return[2,Promise.resolve(this.client.setDeviceId(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserProperty=function(e,t){return u(this,void 0,void 0,function(){var r=this;return c(this,function(n){return[2,Promise.resolve(this.client.setUserProperty(e,t)).then(function(){r.emitUserUpdated()})]})})},r.prototype.setUserProperties=function(e){return u(this,void 0,void 0,function(){var t=this;return c(this,function(r){return[2,Promise.resolve(this.client.setUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.updateUserProperties=function(e){return u(this,void 0,void 0,function(){var t=this;return c(this,function(r){return[2,Promise.resolve(this.client.updateUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.updatePushSubscriptions=function(e){return Promise.resolve(this.client.updatePushSubscriptions(e))},r.prototype.updateSmsSubscriptions=function(e){return Promise.resolve(this.client.updateSmsSubscriptions(e))},r.prototype.updateKakaoSubscriptions=function(e){return Promise.resolve(this.client.updateKakaoSubscriptions(e))},r.prototype.setPhoneNumber=function(e){return Promise.resolve(this.client.setPhoneNumber(e))},r.prototype.unsetPhoneNumber=function(){return Promise.resolve(this.client.unsetPhoneNumber())},r.prototype.resetUser=function(){return u(this,void 0,void 0,function(){var e=this;return c(this,function(t){return[2,Promise.resolve(this.client.resetUser()).then(function(){e.emitUserUpdated()})]})})},r.prototype.variation=function(e){return Promise.resolve(this.client.variation(e))},r.prototype.variationDetail=function(e){return Promise.resolve(this.client.variationDetail(e))},r.prototype.isFeatureOn=function(e){return Promise.resolve(this.client.isFeatureOn(e))},r.prototype.featureFlagDetail=function(e){return Promise.resolve(this.client.featureFlagDetail(e))},r.prototype.track=function(e){return Promise.resolve(this.client.track(e))},r.prototype.trackPageView=function(e){return Promise.resolve(this.client.trackPageView(e))},r.prototype.remoteConfig=function(){var e=this;return new f(function(t,r){var n=e.client.remoteConfig().get(t,r);return Promise.resolve({configValue:n})})},r.prototype.showUserExplorer=function(){return Promise.resolve(this.client.showUserExplorer())},r.prototype.hideUserExplorer=function(){return Promise.resolve(this.client.hideUserExplorer())},r.prototype.fetch=function(){return Promise.resolve(this.client.fetch())},r.prototype.onInitialized=function(e){return this.client.onInitialized(e)},r}(a);export{d as default};
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@hackler/javascript-sdk"),require("uuid")):"function"==typeof define&&define.amd?define(["@hackler/javascript-sdk","uuid"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).HackleManager=t(e.Hackle,e.uuid)}(this,function(e,t){"use strict";var r=function(e,t){return r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])},r(e,t)};function n(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}function o(e,t,r,n){return new(r||(r=Promise))(function(o,i){function s(e){try{c(n.next(e))}catch(e){i(e)}}function u(e){try{c(n.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r(function(e){e(t)})).then(s,u)}c((n=n.apply(e,t||[])).next())})}function i(e,t){var r,n,o,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},s=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return s.next=u(0),s.throw=u(1),s.return=u(2),"function"==typeof Symbol&&(s[Symbol.iterator]=function(){return this}),s;function u(u){return function(c){return function(u){if(r)throw new TypeError("Generator is already executing.");for(;s&&(s=0,u[0]&&(i=0)),i;)try{if(r=1,n&&(o=2&u[0]?n.return:u[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,u[1])).done)return o;switch(n=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return i.label++,{value:u[1],done:!1};case 5:i.label++,n=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){i=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){i.label=u[1];break}if(6===u[0]&&i.label<o[1]){i.label=o[1],o=u;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(u);break}o[2]&&i.ops.pop(),i.trys.pop();continue}u=t.call(e,i)}catch(e){u=[6,e],n=0}finally{r=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,c])}}}"function"==typeof SuppressedError&&SuppressedError;var s=function(){function e(){this.listeners={}}return e.prototype.on=function(e,t){this.listeners[e]=(this.listeners[e]||[]).concat(t)},e.prototype.off=function(e,t){this.listeners[e]=(this.listeners[e]||[]).filter(function(e){return e!==t})},e.prototype.emit=function(e,t){(this.listeners[e]||[]).forEach(function(e){e(t)})},e}(),u=function(){function e(e){this.parameters=e,this.parameters=e}return e.prototype.get=function(e,t){var r=this.parameters[e];return null==r?t:null==t||typeof r==typeof t?r:t},e}(),c=function(){function e(e){this.configFetcher=e,this.configFetcher=e}return e.prototype.get=function(e,t){return o(this,void 0,void 0,function(){var r,n,o;return i(this,function(i){switch(i.label){case 0:return i.trys.push([0,2,,3]),[4,this.configFetcher(e,t)];case 1:if(!(r=i.sent()))throw new Error("invoke result data not exists");switch(n=r.configValue,typeof t){case"number":return[2,Number(n)];case"boolean":return[2,Boolean(n)];default:return[2,n]}case 2:return o=i.sent(),console.error("Unexpected exception while deciding remote config parameter[".concat(e,"]. Returning default value. : ").concat(o)),[2,t];case 3:return[2]}})})},e}();function a(e,t){var r=t.timeoutMillis,n=void 0===r?5e3:r,o=t.onTimeout;return new Promise(function(t,r){e(t,r),setTimeout(function(){o(t,r)},n)})}var p=function(){function e(){this.injectFlag="_hackle_injected"}return e.prototype.isInjectedEnvironment=function(){return!("undefined"==typeof window||!window.ReactNativeWebView)&&!0===window[this.injectFlag]},e.prototype.createInstance=function(e,t){if(this.isInjectedEnvironment()){var r=new f(window.ReactNativeWebView);return new l(e,t,r)}return new d(e,t)},e}(),f=function(){function e(e){this.port=e,this.cleanUp=function(){}}return e.prototype.addEventListener=function(e){window.addEventListener("message",e,!0),this.cleanUp=function(){return window.removeEventListener("message",e,!0)}},e}(),l=function(r){function s(e,t,n){var o=r.call(this)||this;return o.sdkKey=e,o.config=t,o.messageTransceiver=n,o.messageFieldName="_hackle_message",o.resolverRecord=new Map,o.messageTransceiver.addEventListener(function(e){var t,r=e;if(r.data&&"undefined"!==r.data)try{var n=JSON.parse(r.data);if(o.messageFieldName in n){var i=n[o.messageFieldName],s=i.id,u=i.payload;s&&(null===(t=o.resolverRecord.get(s))||void 0===t||t(u),o.resolverRecord.delete(s))}}catch(e){console.log("[DEBUG] Hackle: Failed to parse message. If message not sent by hackle, please ignore this. ".concat(e))}}),o}return n(s,r),s.prototype.onInitialized=function(e){return Promise.resolve({success:!0})},s.prototype.createMessage=function(e,t,r){var n;return JSON.stringify(((n={})[this.messageFieldName]={id:e,type:t,payload:r},n))},s.prototype.createId=function(){return t.v4()},s.prototype.getSessionId=function(){return o(this,void 0,void 0,function(){var e,t=this;return i(this,function(r){switch(r.label){case 0:return e=this.createId(),[4,a(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"getSessionId",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e({sessionId:""})}})];case 1:return[2,r.sent().sessionId]}})})},s.prototype.getUser=function(){return o(this,void 0,void 0,function(){var e,t=this;return i(this,function(r){switch(r.label){case 0:return e=this.createId(),[4,a(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"getUser",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e({user:{}})}})];case 1:return[2,r.sent().user]}})})},s.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},s.prototype.setUser=function(e){return o(this,void 0,void 0,function(){var t,r=this;return i(this,function(n){return t=this.createId(),[2,a(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setUser",{user:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.setUserId=function(e){return o(this,void 0,void 0,function(){var t,r=this;return i(this,function(n){return t=this.createId(),[2,a(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setUserId",{userId:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.setDeviceId=function(e){return o(this,void 0,void 0,function(){var t,r=this;return i(this,function(n){return t=this.createId(),[2,a(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setDeviceId",{deviceId:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.setUserProperty=function(e,t){return o(this,void 0,void 0,function(){var r,n=this;return i(this,function(o){return r=this.createId(),[2,a(function(o){n.messageTransceiver.port.postMessage(n.createMessage(r,"setUserProperty",{key:e,value:t})),n.resolverRecord.set(r,o)},{onTimeout:function(e){return e()}}).then(function(){n.emitUserUpdated()})]})})},s.prototype.setUserProperties=function(e){return o(this,void 0,void 0,function(){var t,r=this;return i(this,function(n){return t=this.createId(),[2,a(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"setUserProperties",{properties:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.updateUserProperties=function(e){return o(this,void 0,void 0,function(){var t,r=this;return i(this,function(n){return t=this.createId(),[2,a(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"updateUserProperties",{operations:e.toRecord()})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e()}}).then(function(){r.emitUserUpdated()})]})})},s.prototype.updatePushSubscriptions=function(e){var t=this,r=this.createId();return a(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"updatePushSubscriptions",{operations:e.toRecord()})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.updateSmsSubscriptions=function(e){var t=this,r=this.createId();return a(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"updateSmsSubscriptions",{operations:e.toRecord()})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.updateKakaoSubscriptions=function(e){var t=this,r=this.createId();return a(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"updateKakaoSubscriptions",{operations:e.toRecord()})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.setPhoneNumber=function(e){var t=this,r=this.createId();return a(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"setPhoneNumber",{phoneNumber:e})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.unsetPhoneNumber=function(){var e=this,t=this.createId();return a(function(r){e.messageTransceiver.port.postMessage(e.createMessage(t,"unsetPhoneNumber",null)),e.resolverRecord.set(t,r)},{onTimeout:function(e){return e()}})},s.prototype.resetUser=function(){return o(this,void 0,void 0,function(){var e,t=this;return i(this,function(r){return e=this.createId(),[2,a(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"resetUser",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e()}}).then(function(){t.emitUserUpdated()})]})})},s.prototype.variation=function(e){return o(this,void 0,void 0,function(){var t,r=this;return i(this,function(n){switch(n.label){case 0:return t=this.createId(),[4,a(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"variation",{experimentKey:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e({variation:"A"})}})];case 1:return[2,n.sent().variation]}})})},s.prototype.variationDetail=function(t){return o(this,void 0,void 0,function(){var r,n,o,s,c,p=this;return i(this,function(i){switch(i.label){case 0:r=this.createId(),i.label=1;case 1:return i.trys.push([1,3,,4]),[4,a(function(e){p.messageTransceiver.port.postMessage(p.createMessage(r,"variationDetail",{experimentKey:t})),p.resolverRecord.set(r,e)},{onTimeout:function(e,t){return t()}})];case 2:return n=i.sent(),o=n.variation,s=n.reason,c=n.parameters,[2,e.Decision.of(o,s,new u(null!=c?c:{}))];case 3:return i.sent(),[2,e.Decision.of("A",e.DecisionReason.EXCEPTION)];case 4:return[2]}})})},s.prototype.isFeatureOn=function(e){return o(this,void 0,void 0,function(){var t,r=this;return i(this,function(n){switch(n.label){case 0:return t=this.createId(),[4,a(function(n){r.messageTransceiver.port.postMessage(r.createMessage(t,"isFeatureOn",{featureKey:e})),r.resolverRecord.set(t,n)},{onTimeout:function(e){return e({isOn:!1})}})];case 1:return[2,n.sent().isOn]}})})},s.prototype.featureFlagDetail=function(t){return o(this,void 0,void 0,function(){var r,n,o,s,c,p=this;return i(this,function(i){switch(i.label){case 0:r=this.createId(),i.label=1;case 1:return i.trys.push([1,3,,4]),[4,a(function(e){p.messageTransceiver.port.postMessage(p.createMessage(r,"featureFlagDetail",{featureKey:t})),p.resolverRecord.set(r,e)},{onTimeout:function(e,t){return t()}})];case 2:return n=i.sent(),o=n.isOn,s=n.reason,c=n.parameters,[2,new e.FeatureFlagDecision(o,s,new u(null!=c?c:{}),void 0)];case 3:return i.sent(),[2,e.FeatureFlagDecision.off(e.DecisionReason.EXCEPTION)];case 4:return[2]}})})},s.prototype.track=function(e){var t=this,r=this.createId();return a(function(n){t.messageTransceiver.port.postMessage(t.createMessage(r,"track",{event:e})),t.resolverRecord.set(r,n)},{onTimeout:function(e){return e()}})},s.prototype.trackPageView=function(){return o(this,void 0,void 0,function(){return i(this,function(e){return[2]})})},s.prototype.remoteConfig=function(){var e=this;return new c(function(t,r){var n=e.createId();return a(function(o){e.messageTransceiver.port.postMessage(e.createMessage(n,"remoteConfig",{key:t,defaultValue:r})),e.resolverRecord.set(n,o)},{onTimeout:function(e){return e(r)}})})},s.prototype.showUserExplorer=function(){var e=this,t=this.createId();return a(function(r){e.messageTransceiver.port.postMessage(e.createMessage(t,"showUserExplorer",null)),e.resolverRecord.set(t,r)},{onTimeout:function(e){return e()}})},s.prototype.hideUserExplorer=function(){return o(this,void 0,void 0,function(){var e,t=this;return i(this,function(r){return e=this.createId(),[2,a(function(r){t.messageTransceiver.port.postMessage(t.createMessage(e,"hideUserExplorer",null)),t.resolverRecord.set(e,r)},{onTimeout:function(e){return e()}})]})})},s.prototype.fetch=function(){var e=this,t=this.createId();return a(function(r){e.messageTransceiver.port.postMessage(e.createMessage(t,"fetch",null)),e.resolverRecord.set(t,r)},{onTimeout:function(e){return e()}})},s}(s),d=function(t){function r(r,n){var o=t.call(this)||this;return o.client=e.createInstance(r,n),o}return n(r,t),r.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},r.prototype.getSessionId=function(){return Promise.resolve(this.client.getSessionId())},r.prototype.getUser=function(){return Promise.resolve(this.client.getUser())},r.prototype.setUser=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(r){return[2,Promise.resolve(this.client.setUser(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserId=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(r){return[2,Promise.resolve(this.client.setUserId(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setDeviceId=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(r){return[2,Promise.resolve(this.client.setDeviceId(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserProperty=function(e,t){return o(this,void 0,void 0,function(){var r=this;return i(this,function(n){return[2,Promise.resolve(this.client.setUserProperty(e,t)).then(function(){r.emitUserUpdated()})]})})},r.prototype.setUserProperties=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(r){return[2,Promise.resolve(this.client.setUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.updateUserProperties=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(r){return[2,Promise.resolve(this.client.updateUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.updatePushSubscriptions=function(e){return Promise.resolve(this.client.updatePushSubscriptions(e))},r.prototype.updateSmsSubscriptions=function(e){return Promise.resolve(this.client.updateSmsSubscriptions(e))},r.prototype.updateKakaoSubscriptions=function(e){return Promise.resolve(this.client.updateKakaoSubscriptions(e))},r.prototype.setPhoneNumber=function(e){return Promise.resolve(this.client.setPhoneNumber(e))},r.prototype.unsetPhoneNumber=function(){return Promise.resolve(this.client.unsetPhoneNumber())},r.prototype.resetUser=function(){return o(this,void 0,void 0,function(){var e=this;return i(this,function(t){return[2,Promise.resolve(this.client.resetUser()).then(function(){e.emitUserUpdated()})]})})},r.prototype.variation=function(e){return Promise.resolve(this.client.variation(e))},r.prototype.variationDetail=function(e){return Promise.resolve(this.client.variationDetail(e))},r.prototype.isFeatureOn=function(e){return Promise.resolve(this.client.isFeatureOn(e))},r.prototype.featureFlagDetail=function(e){return Promise.resolve(this.client.featureFlagDetail(e))},r.prototype.track=function(e){return Promise.resolve(this.client.track(e))},r.prototype.trackPageView=function(e){return Promise.resolve(this.client.trackPageView(e))},r.prototype.remoteConfig=function(){var e=this;return new c(function(t,r){var n=e.client.remoteConfig().get(t,r);return Promise.resolve({configValue:n})})},r.prototype.showUserExplorer=function(){return Promise.resolve(this.client.showUserExplorer())},r.prototype.hideUserExplorer=function(){return Promise.resolve(this.client.hideUserExplorer())},r.prototype.fetch=function(){return Promise.resolve(this.client.fetch())},r.prototype.onInitialized=function(e){return this.client.onInitialized(e)},r}(s);return p});
์ ์์ค ์ฝ๋๋ฅผ ํ๋ก์ ํธ์ ์ถ๊ฐํฉ๋๋ค.
- esm ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค.
default export
ํํ๋ก ๋ชจ๋์ด ์ ๊ณต๋ฉ๋๋ค. - ๋ชจ๋์ ์ฌ์ฉํ ์ ์๋ ํ๊ฒฝ์ด๋ผ๋ฉด umd๋ฅผ ์ฌ์ฉํ์ธ์.
- ์ ์ญ ์ค์ฝํ์
HackleManager
๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ชจ๋์ด ์ ๊ณต๋ฉ๋๋ค.
- ์ ์ญ ์ค์ฝํ์
์์ค์ฝ๋ ์ฐ๋
์์ค ์ฝ๋๋ฅผ npm package๋ก ์ ๊ณตํ๊ณ ์์ง ์์ต๋๋ค.
์๋์ ๋จ๊ณ๋ณ ์ฐ๋ ๊ฐ์ด๋๋ณด๋ค ๋ ์์ธํ ์ฐ๋ ๋ฐฉ๋ฒ์ ์๋์ ๋ ํฌ์งํ ๋ฆฌ์์ ์์ ๋ฅผ ํตํด ํ์ธํด๋ณด์ธ์.
TypeScript ์ง์
github ์ react-native-webview-integration-js-bridge
๋ฅผ buildํ๋ฉด ํ์
์ ์ธ ํ์ผ (d.ts)๊ฐ emit ๋ฉ๋๋ค.
react-native-webview-nextjs-integration
๋ฅผ ์ฐธ๊ณ ํ์ธ์.
lib
๋๋ ํ ๋ฆฌ๋ฅผ ํ์ฉํด file dependency๋ฅผ ์ฐธ์กฐํ๋ ์์๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ธ์คํด์ค ์์ฑ
์๋์ ๊ฐ์ด createInstance
๋ฅผ ํธ์ถํ๋ฉด ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
import ๊ฒฝ๋ก๋ ์ค์นํ ํ๊ฒฝ์ ๋ฐ๋ผ ๊ธฐ์ ํด์ฃผ์ธ์.
- ์์ฑํ ์ธ์คํด์ค๋ฅผ export ํ์ฌ ์ฌ์ฉํฉ๋๋ค.
import HackleManager from "./web-view-integration";
const manager = new HackleManager();
const hackleClient = manager.createInstance(process.env.NEXT_PUBLIC_HACKLE_SDK_KEY!, {
// debug log toggle
debug: true
});
export default hackleClient;
๋ฉ์๋ ํธ์ถ
๋ชจ๋ ๋ฉ์๋์ ๋ฐํ ํ์ ์ด Promise ์์ ์ธ์งํด์ผ ํฉ๋๋ค.
์ง์ํ๋ ๋ฉ์๋์ ์ข ๋ฅ๋ JavaScript/ReactNative SDK ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
import hackleClient from './client';
async function getVariation() {
const variation = await hackleClient.variation(42);
if (variation === 'A') {
// if variation is A do something...
} else {
// else
}
}
React/Vue/Next.js๋ฅผ ์ฌ์ฉํ๊ณ ์๋์?
React Native WebView ์น์ฑ์ฐ๋ ํ๊ฒฝ์์๋ react-sdk ๊ฐ ์ง์๋์ง ์์ต๋๋ค.React Native์ WebView ํ๊ฒฝ์์๋ react-sdk๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
React Native WebView ์์์ Vue, React, Next.js ๋ฑ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ/ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ์๋์ ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
Examples
React
๊ธฐ์กด์ react-sdk์ Custom hooks์ ์ ์ฌํ ํํ์ hooks๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Example์ ํฌํจ๋ hooks ๋ค์ ์ฐธ๊ณ ํ์ฌ ํ์ํ hooks๋ฅผ ์์ฑํด์ ์ฌ์ฉํ์ธ์.
์ Loading ์ฒ๋ฆฌ๋ฅผ ํด์ผํ๋์?๋ฉ์์ง ์ก์์ ์ ์ง์ฐ์๊ฐ์ด ๊ธธ์ง๋ ์์ผ๋, ๋ก๋ฉ ์ฒ๋ฆฌ๋ฅผ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
- ์คํ(variation)์ ๊ฒฐ๊ณผ ๊ฐ์ ๋ฐ์์จ ์ดํ์ ์ฌ์ฉ์๊ฐ ์ต์ด์ ๋ณธ ๊ฒ๊ณผ ๋ค๋ฅธ ํ๋ฉด์ ๋ณด๊ฒ ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ์ ํฉ๋๋ค.
Github: Source
import useVariation from "../hooks/useVariation";
interface VariationTesterProps {}
export default function VariationTester({}: VariationTesterProps) {
const { data: variation } = useVariation(40, "A");
return <pre style={{ fontSize: 54 }}>{variation}</pre>;
}
import useFeature from "../hooks/useFeature";
interface FeatureTesterProps {}
export default function FeatureTester({}: FeatureTesterProps) {
const { data: isOn } = useFeature(40, false);
return <pre style={{ fontSize: 54 }}>{isOn ? "On" : "Off"}</pre>;
}
import useRemoteConfig from "../hooks/useRemoteConfig";
export default function RemoteConfig() {
const { config } = useRemoteConfig(
"targeting_rule_test",
"String ํ์
์ ๊ธฐ๋ณธ ๊ฐ",
);
return (
<pre style={{ fontSize: 54, height: 400, backgroundColor: "#75be6b" }}>
{config}
</pre>
);
}
import hackleClient from "./modules/client";
export default function CustomTracker() {
return (
<div>
<button
onClick={() =>
hackleClient.track({
key: "click_button",
properties: {
button_name: "custom",
},
})
}>
Track Custom Event
</button>
</div>
);
}
Updated 5 days ago