diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e5b21d2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog +All notable changes to this package will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) + +## [1.0.0] - 2019-01-25 +### This is the first release of Sprite Editor, as a Package diff --git a/CHANGELOG.md.meta b/CHANGELOG.md.meta new file mode 100644 index 0000000..dc19d25 --- /dev/null +++ b/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 159031820126f9a48a67bd5ef94ca53f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..78d15f8 --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45edd7b504e1d5e4cb32eaaedf365224 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AppsFlyerDependencies.xml b/Editor/AppsFlyerDependencies.xml new file mode 100644 index 0000000..63d6cb8 --- /dev/null +++ b/Editor/AppsFlyerDependencies.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Editor/AppsFlyerDependencies.xml.meta b/Editor/AppsFlyerDependencies.xml.meta new file mode 100644 index 0000000..dd1e7b6 --- /dev/null +++ b/Editor/AppsFlyerDependencies.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7fcbc06aebd0c41ad869cd372aa4d4ce +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AppsFlyerObjectEditor.cs b/Editor/AppsFlyerObjectEditor.cs new file mode 100644 index 0000000..a7ff699 --- /dev/null +++ b/Editor/AppsFlyerObjectEditor.cs @@ -0,0 +1,75 @@ +using UnityEditor; +using UnityEngine; + + +[CustomEditor(typeof(AppsFlyerObjectScript))] +[CanEditMultipleObjects] +public class AppsFlyerObjectEditor : Editor +{ + + SerializedProperty devKey; + SerializedProperty appID; + SerializedProperty isDebug; + SerializedProperty getConversionData; + + + void OnEnable() + { + devKey = serializedObject.FindProperty("devKey"); + appID = serializedObject.FindProperty("appID"); + isDebug = serializedObject.FindProperty("isDebug"); + getConversionData = serializedObject.FindProperty("getConversionData"); + } + + + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + + GUILayout.Box((Texture)AssetDatabase.LoadAssetAtPath("Assets/AppsFlyer/Editor/logo.png", typeof(Texture)), new GUILayoutOption[] { GUILayout.Width(600) }); + + EditorGUILayout.Separator(); + EditorGUILayout.HelpBox("Set your devKey and appID to init the AppsFlyer SDK and start tracking. You must modify these fields and provide:\ndevKey - Your application devKey provided by AppsFlyer.\nappId - For iOS only. Your iTunes Application ID.", MessageType.Info); + + EditorGUILayout.PropertyField(devKey); + EditorGUILayout.PropertyField(appID); + EditorGUILayout.Separator(); + EditorGUILayout.HelpBox("Enable get conversion data to allow your app to recive deeplinking callbacks", MessageType.None); + EditorGUILayout.PropertyField(getConversionData); + EditorGUILayout.Separator(); + EditorGUILayout.HelpBox("Debugging should be restricted to development phase only.\n Do not distribute the app to app stores with debugging enabled", MessageType.Warning); + EditorGUILayout.PropertyField(isDebug); + EditorGUILayout.Separator(); + + EditorGUILayout.HelpBox("For more information on setting up AppsFlyer check out our relevant docs.", MessageType.None); + + + if (GUILayout.Button("AppsFlyer Unity Docs", new GUILayoutOption[] { GUILayout.Width(200) })) + { + Application.OpenURL("https://support.appsflyer.com/hc/en-us/articles/213766183-Unity-SDK-integration-for-developers"); + } + + if (GUILayout.Button("AppsFlyer Android Docs", new GUILayoutOption[] { GUILayout.Width(200) })) + { + Application.OpenURL("https://support.appsflyer.com/hc/en-us/articles/207032126-Android-SDK-integration-for-developers"); + } + + if (GUILayout.Button("AppsFlyer iOS Docs", new GUILayoutOption[] { GUILayout.Width(200) })) + { + Application.OpenURL("https://support.appsflyer.com/hc/en-us/articles/207032066-AppsFlyer-SDK-Integration-iOS"); + } + + if (GUILayout.Button("AppsFlyer Deeplinking Docs", new GUILayoutOption[] { GUILayout.Width(200) })) + { + Application.OpenURL("https://support.appsflyer.com/hc/en-us/articles/208874366-OneLink-deep-linking-guide#Setups"); + } + + + + serializedObject.ApplyModifiedProperties(); + } + + +} \ No newline at end of file diff --git a/Editor/AppsFlyerObjectEditor.cs.meta b/Editor/AppsFlyerObjectEditor.cs.meta new file mode 100644 index 0000000..4b70b2e --- /dev/null +++ b/Editor/AppsFlyerObjectEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20ab61d4fa1dd458bb6e8d5e3e1d90d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Unity.AppsFlyer.Editor.asmdef b/Editor/Unity.AppsFlyer.Editor.asmdef new file mode 100644 index 0000000..34dbf83 --- /dev/null +++ b/Editor/Unity.AppsFlyer.Editor.asmdef @@ -0,0 +1,17 @@ +{ + "name": "AppsFlyer.Editor", + "references": [ + "GUID:c3b2ad556d41d1441bfade97a3c348cd" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Editor/Unity.AppsFlyer.Editor.asmdef.meta b/Editor/Unity.AppsFlyer.Editor.asmdef.meta new file mode 100644 index 0000000..6f0477e --- /dev/null +++ b/Editor/Unity.AppsFlyer.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e6960e31ade34ba46811fcd20d1d566d +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/logo.png b/Editor/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..01c2b8cae0fa888c39bc06375382cb4d0f99ab12 GIT binary patch literal 9426 zcmW++bzGC*7ajs4C8&gSNKRTxS~^Auj1K8;0bziEgoPlJ?uL=lqvK1A?iwjb52PD@ zFTXz)pZmV|+!N2O^PDeQ8cM_j)C3?9h*(8gUK<2@00;iJKY9p!!-vH=fFFE!WkW9z zi16wC2WxC0=o$oK1gXfs(fyE$S&-JIQMv0mm@OTgUBVwpZ3285C;6uw)*dFlEtt*zDZnrh$RuCV}?Z+sL4eLJkPjLUCtD|Lj~bGtjl zpzDaXwlye9x%wjvy#?*8> zWdM);fE;*EI;^k&scg7l2=E87|sj+P1eQ#eK)Wi&V2%rWM zx6j<3FfPgGYrTlBW1%L4NdX*)B5l}EEUfz1cE=`yCUyi zVIL+)#1k(-7wm8=5GYtEOlA0~1H^Szu)i`$jF%Dw(*2VEm!5ShalRV}^;GrrW%7_3 z;8AF%z?MpA6v`!4>plo6q--}Tr9cp(7f{)8Q}=HGn3hzo=SOlI;bMV;Gx+Q(S%la! z*lyHjF0AI9xV8P;0oc)k;jFYO!0?^bW;`I!qc45AIUS)XR$J^2tC;F(v8gUaz|9Zh zRD63T66Yzr0O+>8?8yD}!WrValPzxee#{>Qh{5T|WeqQEjrAY35OgU6=J!nSYj}JE zyi3-Yh`E1J6IPl-5|`tLKAsk2Sbx(o5GQGTrL;6iaCi0I>$dmD8<~#k-b2X7UDD89 z<>k29PSLp}(AhiQW}0HjcRtLCckF=XV{zwJ7`yVVoqGv+-)NJIk(4P|hW=7y7#0;Y zarWWutE<_;i`ARC)`z6zE(0+cS6TjeZUnj9{TV$El;y+u95w{YZnp;TO8rHiLXQEEJjfcA#*IO{b9Yp zsG*Ck1Rt4dyCg=>Zl|xgaP>h#0!-RE2~y8kuzYpdNOD)AtrlVE$u9^$R1G2ZAi8zO z`=h~?r9u9)wn_WN7HD29GEOGEI>vLLnzfAt43Er-tu~de*6c&LOP={LoOftU6 zoqoW`=amL5Shhw(OE@ZR3>_>1qACt4U87BO+^I!&5O5Ug4InDyE@L+R)=ElIA(-UC0(tMjdM2M$i~7aUZoU(~B+ zTM#QLONisOs(4t`K+Nh*1dUjf<=HonJ!|kAfwKq%KDL(=Y{)q)v*@6{!XJ0D0fAoXs zY5F@owT0C5jM?(jgksGUnK@9w#$?>ubHn;Dl&y_q$tr6ltY295-uF(ocIf< zIQT3M)pCoCtt^t&mMC2}1H)PMa9yX1#37D0)zQ=cGQ0m6W1G^0g;J#kZqew*eGBR@ zv)mibid^12(N=p}SpWUek8mY9Tz$Uv<(E~hG0``rK0P+b=Kz@3?aVAW zOCA4R)P>vN*~pn^oGyuGrbaTmVSaQj{!d#w1TeF|HcV2H!p+@=80-)lmW?{ZN$U{} zoA0WOD80Ab{$5fKES+eE_l^;k4V-BeUVCA_MZ$V`UbnsJllYLdvimArIpQ}K;l+bg zDLj{Q225z7#vasnWN~WFf#Ik@{qyl{-Q?M|`4_9sZP#~rHCUc>i!CXqMs~W)SR&;X z+DE_lL?gtLw%4LZT++>|xL~s<41zN{rmYQ#Se`(gBSxy-njM%gE%skWZ`!tD69#7W zn6>!_svNZsE!~!H9=C*1DkAX?+a+Q1kW?iGN8X}IdDdHL3CdLXk*^q;VJT^jP}sPP<&KR8cPV+>$Zeh^e5%)MV#VO@T! z>K*%Sw4vdWxdEqI)BD(?>Geliah`zHn}=kD<+(1f#yq1YtbfY|e15=E(h+;3R}8O; zEj9l!Xc`5dadCUxpIiVo5tnH4z{Uw$_tYRVbjCifau8RTTimTPO0(Wu^X+dC!?r)4 zt}S2FBGIaG5BMMsmGc2DAtmIs1+gTI2;sWyB%YOHy{X%4z6nC7c2$_p=l#T8d4EYH z*+cGT(n;hl0fkG$RkFm8OOvYMg;uH=XvOPCz8yb7E&-XVfU!oyUSuL4lBUBcwsTvl_XL_4Z#Vf6a`?hJ$kwH5~EY)8yP8NwY=R>uP?XSF8vF?N;P`j;k z;`XpAw4-oMER7g;Bl? zkZbyfMtGM?ybS}5XIQ+@Fg&29^7%F?FF%pT#(>tD{i2x|(e$JSiB56cSUL0*^L_dG zbqnXj`3#zFQD{97zZE#lyzbH87y6bDZK$J*OtTm}?w}b&WA`YIs2{iry7>}_{K(Q1 zWTzyeJuYb0Bcj}>p}C;vPrud_CRcj)M{uc9U_G$xBAE`iw{$vuv?=Xw3Gc>r-AeDo z=~Uem`)kiTCxs?=qV$vWl&$Ba_Se7Dr01(?S|_mwtEUmxQnjaV>!?Plo!~Lc6Lo^p zJ;TSpPl6WHnp*PWFNApRmJnaL7Em2cL#@*-6$==q@iDIGPRtM=r!M;$%^Ic9(L-PX z?R==qzK;+?{(f8hm1Y%Kf+rMOt5#(z`xW?EqSrBY+`;vltOj5iGbbENr{KkvD5=G* zt7iN3-TI+-MN2!*ayCd|U|SfNJbO9C$YP+UP+%Pdb?u>JR zov>$R%;!aLvxWAg$~5*o86|PCMt%!1RcExg{Y-5+Ve$T3{AY+;0frpED~%9vUu$F; z?8bCbNohSXi0{7fO;2Vl&5wN6V>O)Bkw@^t?+sW)@1@RL%v1PIHM;UF2Dpm?Xd~so z@T8#6>Qpsf0Hoi%DBY|io_#W29gm<7E35uIDA9gqRiulc7BAs&Hr=#%pDFq06ONN4 zBN3Tph@uXzYoU{tJv(*L?nb*nyw=u{sI%#yX)YnHI?}gsB(+i>?830>c&=vTM9Xlr zNH>TkG(AR?6{fJCe!LH+VH$a;^)oRw zka1DkAai96!+QIHN_nX&gEQqcZAZR9k^>L9k8!CYy`1-95{5Zi&0=%>?9WpM$oU1W zm=+i^?D%|7?3ZEYD<7)UsgGWoG4kU@#G}$b(+O?=d#5LtdAv7*D_RbrAuMhCe)5Or z)AY7=i`Y03p)dQl$T0oR6kL(%-(|8#E^5#Az`DZoKef8Hs~T87ki-!fS1EVC|B0MR z-x8fk{dA0{xXP*A-9kEL5_t#Q81{8s>+HzcY-AGWo!+sHQS#h!mPbVA@%ur`qLE7W zp>i3vHD~Zz-xKC6V2jKFuf8G9JCXU%l19*o`Awz$Od40ZcJq=^q>9UpqPJ(AjynDa zx<7i}0$o<8U%JD10X=8LKq#Y;3KuQZZeu{LC*w zOj9tGye}`em_~-3r)DFN1Gv8>Nv2gh4YHM()V((FQ*(B~ zC%&_h>(fqYgYR)}&`CZ>Sj(KVdYJm+L?>5y!{D?PvhkFn!ZZ` z*%5yZ|HT1k)d!m*QbR|q@AQR`l$5Jj^kv}4A7S*F{VZacoi0*4WCu9mn2}FiH!MFb zSxR&d^17{eaLskm4~|SZQc`4!Y3jHgD>Iuw=1$ybV*N8C4DOSVNWpzwMNJ^C(bHZ# zyoShf6`tA4(bHeIl(H3MlNQ*X+`J5Pju06ND9aVL*j>LK#VKwrqt(A zyt=8s*y4QAZKY^+xVm$*siUuO}MSB@C*1`ZUOSIZ1-C(pUOi9&U^g|0Ew9GWxo z56(59D$^&Ae8Uvic`p_KsLB! z@@x0PXj0B zhYJIrrto!8?MD$WTD$l-Ge&B}JW_%$2>%JoVBg-JwT0}Oc{&9;f}a1_lQuw??NzC3 zt{4&xJyrdhLzj6fdIN(qe!cPpCLJ+#4yK6jr`SFYe)u!B{b-MW6l{ax zO3iBlY=>4y4epE?Bjqj>3=+O0(qvI6krCqR!<51z0>2=JnOm2HCtO53#!@C}WWxo- z0lJq6VR!p~K}AyWNDq{s(K_|5;k4IL`g48L(#M;~^`PVdwKL^6L$!80pURYZT6i0KDnST$a7kLU)wUjd!3n6dfkaqpki?jUIPBeuK zJ~-p5qNn?&Htr#%9bVZ+7UN+|NS~uOiVNfm{b;x`p#bv4`6RKSD4&=SA72J{lQQ zw{eZn!i}q<_CDmf@n{vuQLK?16`g^>Jyk0Vihb-{M}j_WbiKOf@pd&m{d7yAR~jl@(*1ZeXji`2_KsDT z`DyJ2avVE{N@HJx0$ZKk17nBm*H)k}j~e&=ce}hR3DHiI=%qOU1>~{EG!g{y0Pt-; zeL$lgXVh6JJRJ?^Zl-XFZkMx`tFLW8EqGV3^jBcn)!45vx0H0-T6}o^(x|}irzT=3 zGLgnX@re;RrC*czksJVA1RSrZVV?z%XQfj=$68CDQ%l*P-adNz{6Aq#=jlla6kkm^ zT$;=!Jmzbjy7XV*GM29=oq^5GB}_8-G4Tf&x|ASy9QXJs8#L{@@)VaW&9zXY;do9Q zfXe?xBK8#6Y0jT}niJ~7{_}DD;3pX_L)B1FiXS&V+SJTpHXW>0{iwV9&Bm{Y>OsDL z(jj7{P4;Hi?Ejj2T|&RpMj{}#&g0%Ola6bATI3IzV2-inltDwo9X2+MuG zwU({tYfC#S=4VI_yOgHV82mV?S{P2iEKCCk6!UUZFWRAeQmh-dqP-)R?WaCJ37<{A z*u{(Y#S<9V;(yptD37&AT(BP@_yxc@a9!+QWLZB`WJ{H-G1D_JUYM%eh8EFs z=-wK(r}j3{hLu5V2^6z3f^^Qt=a~oHxL_W4a9k1P zUoI!xn;p5G6&2&iGA#$6TK=BvK-??=ox*E7;2@_{Bp)uErqiONnSeM?3Htf=xU^LD zA79azH9^!O##&COav&xHm{zF3iMQ7!BF25~!?vPw)m1MR2I`BdrT zuYJwQKS>@CW3OveUtS3flm(LiJ2!jP{6ggW3~_aBn@~p6qL)i&sULT|6Ey|DuT2pP zB>6sNLhr~dEG#~n(s2GuYJ@&BGMoQ(Z2pRA%D>9*&KuO`&Xhxb4BOM$xj!PZ@j~YE z)*k(GKX~WYyjddkA;}ELm36RYaFH{cE>#8gdu{XlC;YiZm)}l+5)t`_9|;~}8iW5B zbRR#7DBxjat!3KYT-2+FPA~e>NZ-b0%;dZC_{V212#viIMu?RsizZAQed;fcz~dl3aw|@E z*4g4WaCo@}!#&red7UX(j7MA*w>-z*`ERncjrE;Nz&j|vE&8CZPNwO&8uw54bj7F1 zmOtKwf)Ij9)Qz6L<(Ux57j8!lUsay*Vf=vqy2%)B0VXF5@AC+*l?_8(mOwEN42=z& zd%D4yh)?LfD71+)LZfdR=2j#OTdbAY)u6bs3a~GefH;N5+(YDtYG z()P4DBbA_sC#iL&YlpOQnLJ^Ab>ax|NHLqeT#;I6^>UBtq$c_?R$~xJg7Ak`b*KUK z?(k}teem1ylP*EXadz^IykEJ{c_q*&>Ut3k68uX!>iJRj)_m%=edW2!LFe=X@(kyX-JZiEhs~YW z3*&Sf8sQuL-+6g5O@9Xa%a5r|Y+l<7F?0%t$46_!Gve?+qgk`DC z_)n*CO${+DSjm|fN7R~9TVsT}3(NX)ku%4$bujh>5xV7_W=aVya0xQ3up|^Y%`W!v zjhs4@azpBV=M2o5LNE9ZdD^w`2u^Q5Gga#-GB1d;E9YD3o-|bX3i5U5WZ6+C^B6^| zc0-gPRobuXLt4TOv0dU7dl-`j z)Y-1e;gQ5XYDYb_j=oQ`sq^W~P4cUD18)#44HN~C%qEg2nLtC&-Z<3hMPUdkk+@j#B7c-3QX&>Xm{xhoA?J|oD7Se1L#8pYaYqR^tv=Q{h<;mbl z?{1hE#wjRU&xJ&_X=Bg?W!bI5mA+e%V_pkR!f-+JF(j!LijIRDz4D6)%uoJ!li@Lku=Dsel z89v~u3GaIwhDv=f;q=+j-sy9BUoPyOkta`pI$!9&IfVESGOww7e_I*xI2TuFhE)%AiUq?67{T z;FTSl$=*0gZY%Eg?k7KaUwC(+Sc`re z@2k`S2bt_Z!u3e1il;O5g0nRiNCq{siQ(t`e!i(oF+c|Y>RM%RUJF2soa_-~P-`pk z^)Ds%k9Xne$)0ovt|ET+j{|uYks7a*NxN|FAaU+Se;Un-v@c4&E{vw8=r-2q zV+euhU}-xty@#F*F)J@#J%p~-I%vlXXgm7-%G|-JeRZp2Q9%~IadvVG#_RuNT{$lP z2<|aA$@$S6emQ{%oab=o2(>;6wbs6QrIWKV-v3#@f9YbL&{*#8LT@8B3j@om4(ovG zOP8g-X$JNb1e_DYa$J`6^29^b%Og-NX26wZ2A3&bK~G67i?!RwWthn<0sJdX`DNw0 zuaugkvTYcu-adVeNwRXWWH+O4UWNAC^f#x@#@A~W4GtS9Ixp7ZtgogJxwc`%5UyX0 zmVx+@pxs1*Cg<=^69s^gTUVKzm-*(!-tWu`jU+_C4Swsg?v<>(ydCtLcYK%VI_DmQ zA>&w5A`+6PEbo)^zgg~`VN{;xRW4+7)z2!2q%RJm-MqC@;;68AA3nEdkw-b1-7|F1hdb_056t4SR67@KnKm(Vl$}P~ zcIkOjG1sJFs7LSF38w>5co*x(4On@C9yhwi{Y=dH;158~e2mnfR|~28`C1MOjBs2V zys%P&ri^3>ko-)0sQ1F0S}c`;oEXbjaMviVNeu9{8C3PC>Q1YT(D1Y0=&*fKh96|I zmpM6px_t}aIIu`qEhxzfEq^pEHP`=al6UbHo80zrCpDV*d3<>3 za~ghux$eQOvHZlR z)1r!n-2F3|UmH=_=vMuhGcB_`-7BP%CT!cTfg%w$E;`khx*pTA7=3a@S?+yB&zx~0 z;ujdLFY%qO>t;W}ZK9NXLY3ya-I|DgH8yFt@*JEv-+-C?q7&tuif zJ`jFGDezIW8yQ^&aJ6>&0JF%Tn>LUk3d!5|V(zii5oDcW40OAzO6U%J?L;bZhv>V?!2|A%~g9ie!MDQ8% z|DU)%Zua6V{Uv2VCkjDBOCjC@ zc~by~Do9}=5F>NX*Om<=&^qpP=-%_Tj96hP&_p`BJfPltKGinZ`zUU7qm`=+1`5FY`h~nE)0;BK9H#CNx7HgQjz1LhS3}uTn zDALFmru@AvIRx;+^kJxV&Y`q`zRF#mtQYTU4JC~4s}%}~Eykh^Wy??0eJeTkxLzqc zr*!q#3yIY(Lw2g=3?PvFy?WYLW0Y+CufSRm8C;(1cDkROO1p+HA|9@FXg?u8>i}k?V1pK`K0Itjmi9|Al z#+IcTW|}Z=y;-0*g!d7A#bo;AlW+Ybp9CO=G7Kf7d-Kg|P{aeWlUXNU!5FDCL)TUP;I2VVnaFCvfMD*!BxVT_kiyXMZACQxvr z8`5W8gRmzDPzM5OQGwy)I{?pYbCMz>Jt@exUlK?GQ2L}`_#~l_Z*2D(;1JI+)K_&_ zX;KlR|7{UhJz!l8BV?-cY#t>Qg#v(2_XsYe<$X9bu9?pd00szorIZu`J`A|c|NoYf zGeM@TfvN*lJ@$nE_xFAQnJPB7OzBd?1?q$Dq2QD|IV~5d?_TVe0Jx@x88YQ&Zq=E7Z(q~}!!Hmdz z^?Tb$>A>(Ovv1Rya_-&p`AHnA-kIRLAR8cUlo_HZj|p0&)bo{2^ov!O2C5$zwGHEM Zqz@UJ#ov8pVgr-_sVHd3m&v{h{U4`cTj~G+ literal 0 HcmV?d00001 diff --git a/Editor/logo.png.meta b/Editor/logo.png.meta new file mode 100644 index 0000000..dff741e --- /dev/null +++ b/Editor/logo.png.meta @@ -0,0 +1,90 @@ +fileFormatVersion: 2 +guid: 473067080fc4c40af95704043da99f96 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 10 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..58d6be4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,2 @@ +# WTFPL +Do whatever the fuck you want with this \ No newline at end of file diff --git a/LICENSE.md.meta b/LICENSE.md.meta new file mode 100644 index 0000000..a7d9402 --- /dev/null +++ b/LICENSE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d549868ce7709584c862065ae73f29cd +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins.meta b/Plugins.meta new file mode 100644 index 0000000..be984c0 --- /dev/null +++ b/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0518f4b43994d374aaa3e77220a77f58 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS.meta b/Plugins/iOS.meta new file mode 100644 index 0000000..792ac5a --- /dev/null +++ b/Plugins/iOS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0f28460dd63504fd788e321ebe417c9e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/AFUnityUtils.mm b/Plugins/iOS/AFUnityUtils.mm new file mode 100644 index 0000000..6ca9c96 --- /dev/null +++ b/Plugins/iOS/AFUnityUtils.mm @@ -0,0 +1,100 @@ +// +// AFUnityUtils.mm +// Unity-iPhone +// +// Created by Jonathan Wesfield on 24/07/2019. +// + +#if __has_include() +#import +#else +#import "AppsFlyerTracker.h" +#endif + + +static NSString* stringFromChar(const char *str) { + return str ? [NSString stringWithUTF8String:str] : nil; +} + +static NSDictionary* dictionaryFromJson(const char *jsonString) { + if(jsonString){ + NSData *jsonData = [[NSData alloc] initWithBytes:jsonString length:strlen(jsonString)]; + NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil]; + return dictionary; + } + + return nil; +} + +static const char* stringFromdictionary(NSDictionary* dictionary) { + if(dictionary){ + NSError * err; + NSData * jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&err]; + NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + return [myString UTF8String]; + } + + return nil; +} + + +static NSArray *NSArrayFromCArray(int length, const char **arr) { + NSMutableArray *res = [[NSMutableArray alloc] init]; + for(int i = 0; i < length; i++) { + if (arr[i]) { + [res addObject:[NSString stringWithUTF8String:arr[i]]]; + } + } + + return res; +} + +static char* getCString(const char* string){ + if (string == NULL){ + return NULL; + } + + char* res = (char*)malloc(strlen(string) + 1); + strcpy(res, string); + + return res; +} + +static AppsFlyerLinkGenerator* generatorFromDictionary(NSDictionary* dictionary, AppsFlyerLinkGenerator* generator) { + + NSArray* generatorKeys = @[@"channel", @"customerID", @"campaign", @"referrerName", @"referrerImageUrl", @"deeplinkPath", @"baseDeeplink", @"brandDomain"]; + + NSMutableDictionary* mutableDictionary = [dictionary mutableCopy]; + + [generator setChannel:[dictionary objectForKey: @"channel"]]; + [generator setReferrerCustomerId:[dictionary objectForKey: @"customerID"]]; + [generator setCampaign:[dictionary objectForKey: @"campaign"]]; + [generator setReferrerName:[dictionary objectForKey: @"referrerName"]]; + [generator setReferrerImageURL:[dictionary objectForKey: @"referrerImageUrl"]]; + [generator setDeeplinkPath:[dictionary objectForKey: @"deeplinkPath"]]; + [generator setBaseDeeplink:[dictionary objectForKey: @"baseDeeplink"]]; + [generator setBrandDomain:[dictionary objectForKey: @"brandDomain"]]; + + + [mutableDictionary removeObjectsForKeys:generatorKeys]; + + [generator addParameters:mutableDictionary]; + + return generator; +} + +static EmailCryptType emailCryptTypeFromInt(int emailCryptTypeInt){ + + EmailCryptType emailCryptType; + switch (emailCryptTypeInt){ + case 1: + emailCryptType = EmailCryptTypeSHA256; + break; + default: + emailCryptType = EmailCryptTypeNone; + break; + } + + return emailCryptType; +} + diff --git a/Plugins/iOS/AFUnityUtils.mm.meta b/Plugins/iOS/AFUnityUtils.mm.meta new file mode 100644 index 0000000..14b3343 --- /dev/null +++ b/Plugins/iOS/AFUnityUtils.mm.meta @@ -0,0 +1,37 @@ +fileFormatVersion: 2 +guid: af70a8605208f4a56bea5aecf826811d +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: {} + - first: + tvOS: tvOS + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/AppsFlyer+AppController.m b/Plugins/iOS/AppsFlyer+AppController.m new file mode 100644 index 0000000..a8471c8 --- /dev/null +++ b/Plugins/iOS/AppsFlyer+AppController.m @@ -0,0 +1,140 @@ +// +// AppsFlyer+AppController.m +// Unity-iPhone +// +// Created by Jonathan Wesfield on 24/07/2019. +// + +#import +#import "UnityAppController.h" +#if __has_include() +#import +#else +#import "AppsFlyerTracker.h" +#endif + + +@implementation UnityAppController (AppsFlyerSwizzledAppController) + +static BOOL didEnteredBackGround __unused; +static IMP __original_applicationDidBecomeActive_Imp __unused; +static IMP __original_applicationDidEnterBackground_Imp __unused; +static IMP __original_didReceiveRemoteNotification_Imp __unused; +static IMP __original_continueUserActivity_Imp __unused; +static IMP __original_openUrl_Imp __unused; + + ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + + /** + Method method1 = class_getInstanceMethod([self class], @selector(applicationDidBecomeActive:)); + __original_applicationDidBecomeActive_Imp = method_setImplementation(method1, (IMP)__swizzled_applicationDidBecomeActive); + */ + + /** + Method method2 = class_getInstanceMethod([self class], @selector(applicationDidEnterBackground:)); + __original_applicationDidEnterBackground_Imp = method_setImplementation(method2, (IMP)__swizzled_applicationDidEnterBackground); + */ + + /** + Method method3 = class_getInstanceMethod([self class], @selector(didReceiveRemoteNotification:)); + __original_didReceiveRemoteNotification_Imp = method_setImplementation(method3, (IMP)__swizzled_didReceiveRemoteNotification); + */ + + /** + Method method4 = class_getInstanceMethod([self class], @selector(application:openURL:options:)); + __original_openUrl_Imp = method_setImplementation(method4, (IMP)__swizzled_openURL); + */ + + /** + [self swizzleContinueUserActivity:[self class]]; + */ + + }); +} + +/** ++(void)swizzleContinueUserActivity:(Class)class { + + SEL originalSelector = @selector(application:continueUserActivity:restorationHandler:); + + Method defaultMethod = class_getInstanceMethod(class, originalSelector); + Method swizzledMethod = class_getInstanceMethod(class, @selector(__swizzled_continueUserActivity)); + + BOOL isMethodExists = !class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); + + if (isMethodExists) { + __original_continueUserActivity_Imp = method_setImplementation(defaultMethod, (IMP)__swizzled_continueUserActivity); + } else { + class_replaceMethod(class, originalSelector, (IMP)__swizzled_continueUserActivity, method_getTypeEncoding(swizzledMethod)); + } +} + + BOOL __swizzled_continueUserActivity(id self, SEL _cmd, UIApplication* application, NSUserActivity* userActivity, void (^restorationHandler)(NSArray*)) { + NSLog(@"swizzled continueUserActivity"); + [[AppsFlyerTracker sharedTracker] continueUserActivity:userActivity restorationHandler:restorationHandler]; + + if(__original_continueUserActivity_Imp){ + return ((BOOL(*)(id, SEL, UIApplication*, NSUserActivity*))__original_continueUserActivity_Imp)(self, _cmd, application, userActivity); + } + + return YES; + } + +*/ + +/** +void __swizzled_applicationDidBecomeActive(id self, SEL _cmd, UIApplication* launchOptions) { + NSLog(@"swizzled applicationDidBecomeActive"); + + if(didEnteredBackGround){ + [[AppsFlyerTracker sharedTracker] trackAppLaunch]; + } + + if(__original_applicationDidBecomeActive_Imp){ + ((void(*)(id,SEL, UIApplication*))__original_applicationDidBecomeActive_Imp)(self, _cmd, launchOptions); + } +} + */ + +/** +void __swizzled_applicationDidEnterBackground(id self, SEL _cmd, UIApplication* application) { + NSLog(@"swizzled applicationDidEnterBackground"); + didEnteredBackGround = YES; + if(__original_applicationDidEnterBackground_Imp){ + ((void(*)(id,SEL, UIApplication*))__original_applicationDidEnterBackground_Imp)(self, _cmd, application); + } +} + */ + +/** +BOOL __swizzled_didReceiveRemoteNotification(id self, SEL _cmd, UIApplication* application, NSDictionary* userInfo,void (^UIBackgroundFetchResult)(void) ) { + NSLog(@"swizzled didReceiveRemoteNotification"); + + [[AppsFlyerTracker sharedTracker] handlePushNotification:userInfo]; + + if(__original_didReceiveRemoteNotification_Imp){ + return ((BOOL(*)(id, SEL, UIApplication*, NSDictionary*, (UIBackgroundFetchResult)))__original_didReceiveRemoteNotification_Imp)(self, _cmd, application, userInfo, nil); + } + return YES; +} + */ + +/** +BOOL __swizzled_openURL(id self, SEL _cmd, UIApplication* application, NSURL* url, NSDictionary * options) { + NSLog(@"swizzled openURL"); + [[AppsFlyerTracker sharedTracker] handleOpenUrl:url options:options]; + if(__original_openUrl_Imp){ + return ((BOOL(*)(id, SEL, UIApplication*, NSURL*, NSDictionary*))__original_openUrl_Imp)(self, _cmd, application, url, options); + } + return YES; +} +*/ + +@end + + + + diff --git a/Plugins/iOS/AppsFlyer+AppController.m.meta b/Plugins/iOS/AppsFlyer+AppController.m.meta new file mode 100644 index 0000000..b342cf8 --- /dev/null +++ b/Plugins/iOS/AppsFlyer+AppController.m.meta @@ -0,0 +1,37 @@ +fileFormatVersion: 2 +guid: 55a0a9d0e05fe48158b3cb8cee7b6aaa +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: {} + - first: + tvOS: tvOS + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/AppsFlyerAppController.mm b/Plugins/iOS/AppsFlyerAppController.mm new file mode 100644 index 0000000..eb93d8f --- /dev/null +++ b/Plugins/iOS/AppsFlyerAppController.mm @@ -0,0 +1,119 @@ +// +// AppsFlyerAppController.mm +// Unity-iPhone +// +// Created by Jonathan Wesfield on 30/07/2019. +// + +#import +#import "UnityAppController.h" +#import "AppDelegateListener.h" +#if __has_include() +#import +#else +#import "AppsFlyerTracker.h" +#endif + +/** + Note if you would like to use method swizzeling see AppsFlyer+AppController.m + If you are using swizzeling then comment out the method that is being swizzeled in AppsFlyerAppController.mm + Only use swizzeling if there are conflicts with other plugins that needs to be resolved. +*/ + +@interface AppsFlyerAppController : UnityAppController +{ + BOOL didEnteredBackGround; +} +@end + +@implementation AppsFlyerAppController + +- (instancetype)init +{ + self = [super init]; + if (self) { + UnityRegisterAppDelegateListener(self); + } + return self; +} + +- (void)didFinishLaunching:(NSNotification*)notification { + NSLog(@"got didFinishLaunching = %@",notification.userInfo); + if (notification.userInfo[@"url"]) { + [self onOpenURL:notification]; + } +} + +-(void)didBecomeActive:(NSNotification*)notification { + NSLog(@"got didBecomeActive(out) = %@", notification.userInfo); + if (didEnteredBackGround == YES) { + [[AppsFlyerTracker sharedTracker] trackAppLaunch]; + didEnteredBackGround = NO; + } +} + +- (void)didEnterBackground:(NSNotification*)notification { + NSLog(@"got didEnterBackground = %@", notification.userInfo); + didEnteredBackGround = YES; +} + +- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler { + [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; + [[AppsFlyerTracker sharedTracker] continueUserActivity:userActivity restorationHandler:restorationHandler]; + return YES; +} + +-(BOOL) application:(UIApplication *)application openUrl:(NSURL *)url options:(NSDictionary *)options { + NSLog(@"got openUrl: %@",url); + [[AppsFlyerTracker sharedTracker] handleOpenUrl:url options:options]; + return YES; +} + +- (void)onOpenURL:(NSNotification*)notification { + NSLog(@"got onOpenURL = %@", notification.userInfo); + NSURL *url = notification.userInfo[@"url"]; + NSString *sourceApplication = notification.userInfo[@"sourceApplication"]; + + if (sourceApplication == nil) { + sourceApplication = @""; + } + + if (url != nil) { + [[AppsFlyerTracker sharedTracker] handleOpenURL:url sourceApplication:sourceApplication withAnnotation:nil]; + } + +} + +- (void)didReceiveRemoteNotification:(NSNotification*)notification { + NSLog(@"got didReceiveRemoteNotification = %@", notification.userInfo); + [[AppsFlyerTracker sharedTracker] handlePushNotification:notification.userInfo]; +} + +@end + +IMPL_APP_CONTROLLER_SUBCLASS(AppsFlyerAppController) + + +/** +Note if you would not like to use IMPL_APP_CONTROLLER_SUBCLASS you can replace it with the code below. + + +(void)load + { + [AppsFlyerAppController plugin]; + } + + // Singleton accessor. + + (AppsFlyerAppController *)plugin + { + static AppsFlyerAppController *sharedInstance = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + + sharedInstance = [[AppsFlyerAppController alloc] init]; + }); + + return sharedInstance; + } + + **/ diff --git a/Plugins/iOS/AppsFlyerAppController.mm.meta b/Plugins/iOS/AppsFlyerAppController.mm.meta new file mode 100644 index 0000000..50360f9 --- /dev/null +++ b/Plugins/iOS/AppsFlyerAppController.mm.meta @@ -0,0 +1,37 @@ +fileFormatVersion: 2 +guid: f78009dc77e7c4608a9b13a0cf6c63e4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: {} + - first: + tvOS: tvOS + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/AppsFlyeriOSWrapper.h b/Plugins/iOS/AppsFlyeriOSWrapper.h new file mode 100644 index 0000000..03ab106 --- /dev/null +++ b/Plugins/iOS/AppsFlyeriOSWrapper.h @@ -0,0 +1,35 @@ +// +// AppsFlyeriOSWarpper.h +// Unity-iPhone +// +// Created by Jonathan Wesfield on 24/07/2019. +// + +#import "AFUnityUtils.mm" +#import "UnityAppController.h" +#if __has_include() +#import +#else +#import "AppsFlyerTracker.h" +#endif + +@interface AppsFlyeriOSWarpper : NSObject + +@end + + +static AppsFlyeriOSWarpper *_AppsFlyerdelegate; +static const int kPushNotificationSize = 32; + +NSString* ConversionDataCallbackObject; + +static const char* VALIDATE_CALLBACK = "didFinishValidateReceipt"; +static const char* VALIDATE_ERROR_CALLBACK = "didFinishValidateReceiptWithError"; +static const char* GCD_CALLBACK = "onConversionDataSuccess"; +static const char* GCD_ERROR_CALLBACK = "onConversionDataFail"; +static const char* OAOA_CALLBACK = "onAppOpenAttribution"; +static const char* OAOA_ERROR_CALLBACK = "onAppOpenAttributionFailure"; +static const char* GENERATE_LINK_CALLBACK = "onInviteLinkGenerated"; +static const char* OPEN_STORE_LINK_CALLBACK = "onOpenStoreLinkGenerated"; + +static NSString* validateObjectName = @""; diff --git a/Plugins/iOS/AppsFlyeriOSWrapper.h.meta b/Plugins/iOS/AppsFlyeriOSWrapper.h.meta new file mode 100644 index 0000000..04eeeb5 --- /dev/null +++ b/Plugins/iOS/AppsFlyeriOSWrapper.h.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: 88eb2a3b8d60c4e1cab4d78d813b2b91 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/AppsFlyeriOSWrapper.mm b/Plugins/iOS/AppsFlyeriOSWrapper.mm new file mode 100644 index 0000000..f312934 --- /dev/null +++ b/Plugins/iOS/AppsFlyeriOSWrapper.mm @@ -0,0 +1,226 @@ +// +// AppsFlyeriOSWarpper.mm +// Unity-iPhone +// +// Created by Jonathan Wesfield on 24/07/2019. +// + +#import "AppsFlyeriOSWrapper.h" + + +static void unityCallBack(NSString* objectName, const char* method, const char* msg) { + if(objectName){ + UnitySendMessage([objectName UTF8String], method, msg); + } +} + +extern "C" { + + const void _startSDK() { + [[AppsFlyerTracker sharedTracker] trackAppLaunch]; + } + + const void _setCustomerUserID (const char* customerUserID) { + [[AppsFlyerTracker sharedTracker] setCustomerUserID:stringFromChar(customerUserID)]; + } + + const void _setAdditionalData (const char* customData) { + [[AppsFlyerTracker sharedTracker] setAdditionalData:dictionaryFromJson(customData)]; + } + + const void _setAppsFlyerDevKey (const char* appsFlyerDevKey) { + [AppsFlyerTracker sharedTracker].appsFlyerDevKey = stringFromChar(appsFlyerDevKey); + } + + const void _setAppleAppID (const char* appleAppID) { + [AppsFlyerTracker sharedTracker].appleAppID = stringFromChar(appleAppID); + } + + const void _setCurrencyCode (const char* currencyCode) { + [[AppsFlyerTracker sharedTracker] setCurrencyCode:stringFromChar(currencyCode)]; + } + + const void _setDisableCollectAppleAdSupport (bool disableAppleAdSupportTracking) { + [AppsFlyerTracker sharedTracker].disableAppleAdSupportTracking = disableAppleAdSupportTracking; + } + + const void _setIsDebug (bool isDebug) { + [AppsFlyerTracker sharedTracker].isDebug = isDebug; + } + + const void _setShouldCollectDeviceName (bool shouldCollectDeviceName) { + [AppsFlyerTracker sharedTracker].shouldCollectDeviceName = shouldCollectDeviceName; + } + + const void _setAppInviteOneLinkID (const char* appInviteOneLinkID) { + [[AppsFlyerTracker sharedTracker] setAppInviteOneLink:stringFromChar(appInviteOneLinkID)]; + } + + const void _anonymizeUser (bool deviceTrackingDisabled) { + [AppsFlyerTracker sharedTracker].deviceTrackingDisabled = deviceTrackingDisabled; + } + + const void _setDisableCollectIAd (bool disableIAdTracking) { + [AppsFlyerTracker sharedTracker].disableIAdTracking = disableIAdTracking; + } + + const void _setUseReceiptValidationSandbox (bool useReceiptValidationSandbox) { + [AppsFlyerTracker sharedTracker].useReceiptValidationSandbox = useReceiptValidationSandbox; + } + + const void _setUseUninstallSandbox (bool useUninstallSandbox) { + [AppsFlyerTracker sharedTracker].useUninstallSandbox = useUninstallSandbox; + } + + const void _setResolveDeepLinkURLs (int length, const char **resolveDeepLinkURLs) { + if(length > 0 && resolveDeepLinkURLs) { + [[AppsFlyerTracker sharedTracker] setResolveDeepLinkURLs:NSArrayFromCArray(length, resolveDeepLinkURLs)]; + } + } + + const void _setOneLinkCustomDomains (int length, const char **oneLinkCustomDomains) { + if(length > 0 && oneLinkCustomDomains) { + [[AppsFlyerTracker sharedTracker] setResolveDeepLinkURLs:NSArrayFromCArray(length, oneLinkCustomDomains)]; + } + } + + const void _afSendEvent (const char* eventName, const char* eventValues) { + [[AppsFlyerTracker sharedTracker] trackEvent:stringFromChar(eventName) withValues:dictionaryFromJson(eventValues)]; + } + + const void _recordLocation (double longitude, double latitude) { + [[AppsFlyerTracker sharedTracker] trackLocation:longitude latitude:latitude]; + } + + const char* _getAppsFlyerId () { + return getCString([[[AppsFlyerTracker sharedTracker] getAppsFlyerUID] UTF8String]); + } + + const void _registerUninstall (unsigned char* deviceToken) { + if(deviceToken){ + NSData* tokenData = [NSData dataWithBytes:(const void *)deviceToken length:sizeof(unsigned char)*kPushNotificationSize]; + [[AppsFlyerTracker sharedTracker] registerUninstall:tokenData]; + } + } + + const void _handlePushNotification (const char* pushPayload) { + [[AppsFlyerTracker sharedTracker] handlePushNotification:dictionaryFromJson(pushPayload)]; + } + + const char* _getSDKVersion () { + return getCString([[[AppsFlyerTracker sharedTracker] getSDKVersion] UTF8String]); + } + + const void _setHost (const char* host, const char* hostPrefix) { + [[AppsFlyerTracker sharedTracker] setHost:stringFromChar(host) withHostPrefix:stringFromChar(hostPrefix)]; + } + + const void _setMinTimeBetweenSessions (int minTimeBetweenSessions) { + [AppsFlyerTracker sharedTracker].minTimeBetweenSessions = minTimeBetweenSessions; + } + + const void _stopSDK (bool isStopTracking) { + [AppsFlyerTracker sharedTracker].isStopTracking = isStopTracking; + } + + const BOOL _isSDKStopped () { + return [AppsFlyerTracker sharedTracker].isStopTracking; + } + + const void _handleOpenUrl(const char *url, const char *sourceApplication, const char *annotation) { + [[AppsFlyerTracker sharedTracker] handleOpenURL:[NSURL URLWithString:stringFromChar(url)] sourceApplication:stringFromChar(sourceApplication) withAnnotation:stringFromChar(annotation)]; + } + + const void _recordCrossPromoteImpression (const char* appID, const char* campaign, const char* parameters) { + [AppsFlyerCrossPromotionHelper trackCrossPromoteImpression:stringFromChar(appID) campaign:stringFromChar(campaign) parameters:dictionaryFromJson(parameters)]; + } + + const void _attributeAndOpenStore (const char* appID, const char* campaign, const char* parameters, const char* objectName) { + [AppsFlyerCrossPromotionHelper + trackAndOpenStore:stringFromChar(appID) + campaign:stringFromChar(campaign) + paramters:dictionaryFromJson(parameters) + openStore:^(NSURLSession * _Nonnull urlSession, NSURL * _Nonnull clickURL) { + unityCallBack(stringFromChar(objectName), OPEN_STORE_LINK_CALLBACK, [clickURL.absoluteString UTF8String]); + + }]; + } + + const void _generateUserInviteLink (const char* parameters, const char* objectName) { + [AppsFlyerShareInviteHelper generateInviteUrlWithLinkGenerator:^AppsFlyerLinkGenerator * _Nonnull(AppsFlyerLinkGenerator * _Nonnull generator) { + return generatorFromDictionary(dictionaryFromJson(parameters), generator); + } completionHandler:^(NSURL * _Nullable url) { + unityCallBack(stringFromChar(objectName), GENERATE_LINK_CALLBACK, [url.absoluteString UTF8String]); + }]; + } + + const void _recordInvite (const char* channel, const char* parameters) { + [AppsFlyerShareInviteHelper trackInvite:stringFromChar(channel) parameters:dictionaryFromJson(parameters)]; + } + + const void _setUserEmails (int emailCryptTypeInt , int length, const char **userEmails) { + if(length > 0 && userEmails) { + [[AppsFlyerTracker sharedTracker] setUserEmails:NSArrayFromCArray(length, userEmails) withCryptType:emailCryptTypeFromInt(emailCryptTypeInt)]; + } + } + + const void _setPhoneNumber (const char* phoneNumber) { + [[AppsFlyerTracker sharedTracker] setPhoneNumber:stringFromChar(phoneNumber)]; + } + + const void _setSharingFilterForAllPartners () { + [[AppsFlyerTracker sharedTracker] setSharingFilterForAllPartners]; + } + + const void _setSharingFilter (int length, const char **partners) { + if(length > 0 && partners) { + [[AppsFlyerTracker sharedTracker] setSharingFilter:NSArrayFromCArray(length, partners)]; + } + } + + const void _validateAndSendInAppPurchase (const char* productIdentifier, const char* price, const char* currency, const char* tranactionId, const char* additionalParameters, const char* objectName) { + + validateObjectName = stringFromChar(objectName); + + [[AppsFlyerTracker sharedTracker] + validateAndTrackInAppPurchase:stringFromChar(productIdentifier) + price:stringFromChar(price) + currency:stringFromChar(currency) + transactionId:stringFromChar(tranactionId) + additionalParameters:dictionaryFromJson(additionalParameters) + success:^(NSDictionary *result){ + unityCallBack(validateObjectName, VALIDATE_CALLBACK, stringFromdictionary(result)); + } failure:^(NSError *error, id response) { + unityCallBack(validateObjectName, VALIDATE_ERROR_CALLBACK, error ? [[error localizedDescription] UTF8String] : "error"); + }]; + } + + const void _getConversionData(const char* objectName) { + if (_AppsFlyerdelegate == nil) { + _AppsFlyerdelegate = [[AppsFlyeriOSWarpper alloc] init]; + } + ConversionDataCallbackObject = stringFromChar(objectName); + [[AppsFlyerTracker sharedTracker] setDelegate:_AppsFlyerdelegate]; + } +} + +@implementation AppsFlyeriOSWarpper + +- (void)onConversionDataSuccess:(NSDictionary *)installData { + unityCallBack(ConversionDataCallbackObject, GCD_CALLBACK, stringFromdictionary(installData)); +} + +- (void)onConversionDataFail:(NSError *)error { + unityCallBack(ConversionDataCallbackObject, GCD_ERROR_CALLBACK, [[error localizedDescription] UTF8String]); +} + +- (void)onAppOpenAttribution:(NSDictionary *)attributionData { + unityCallBack(ConversionDataCallbackObject, OAOA_CALLBACK, stringFromdictionary(attributionData)); +} + +- (void)onAppOpenAttributionFailure:(NSError *)error { + unityCallBack(ConversionDataCallbackObject, OAOA_ERROR_CALLBACK, [[error localizedDescription] UTF8String]); +} + +@end + diff --git a/Plugins/iOS/AppsFlyeriOSWrapper.mm.meta b/Plugins/iOS/AppsFlyeriOSWrapper.mm.meta new file mode 100644 index 0000000..ae5d681 --- /dev/null +++ b/Plugins/iOS/AppsFlyeriOSWrapper.mm.meta @@ -0,0 +1,37 @@ +fileFormatVersion: 2 +guid: dc4c1abadcf544375aabe22e4337d6ee +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: {} + - first: + tvOS: tvOS + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md new file mode 100644 index 0000000..c53ed93 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Readme +Lorem ipsum \ No newline at end of file diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..148c65e --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 96b1ab8c7c887bc4c8337802e5d97ee9 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 0000000..f1af900 --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 131e67461dec612468ec544abeac63e8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AFInAppEvents.cs b/Runtime/AFInAppEvents.cs new file mode 100644 index 0000000..1f6d1fe --- /dev/null +++ b/Runtime/AFInAppEvents.cs @@ -0,0 +1,72 @@ +using UnityEngine; +using System.Collections; + +public class AFInAppEvents { + /** + * Event Type + * */ + public const string LEVEL_ACHIEVED = "af_level_achieved"; + public const string ADD_PAYMENT_INFO = "af_add_payment_info"; + public const string ADD_TO_CART = "af_add_to_cart"; + public const string ADD_TO_WISH_LIST = "af_add_to_wishlist"; + public const string COMPLETE_REGISTRATION = "af_complete_registration"; + public const string TUTORIAL_COMPLETION = "af_tutorial_completion"; + public const string INITIATED_CHECKOUT = "af_initiated_checkout"; + public const string PURCHASE = "af_purchase"; + public const string RATE = "af_rate"; + public const string SEARCH = "af_search"; + public const string SPENT_CREDIT = "af_spent_credits"; + public const string ACHIEVEMENT_UNLOCKED = "af_achievement_unlocked"; + public const string CONTENT_VIEW = "af_content_view"; + public const string TRAVEL_BOOKING = "af_travel_booking"; + public const string SHARE = "af_share"; + public const string INVITE = "af_invite"; + public const string LOGIN = "af_login"; + public const string RE_ENGAGE = "af_re_engage"; + public const string UPDATE = "af_update"; + public const string OPENED_FROM_PUSH_NOTIFICATION = "af_opened_from_push_notification"; + public const string LOCATION_CHANGED = "af_location_changed"; + public const string LOCATION_COORDINATES = "af_location_coordinates"; + public const string ORDER_ID = "af_order_id"; + /** + * Event Parameter Name + * **/ + public const string LEVEL = "af_level"; + public const string SCORE = "af_score"; + public const string SUCCESS = "af_success"; + public const string PRICE = "af_price"; + public const string CONTENT_TYPE = "af_content_type"; + public const string CONTENT_ID = "af_content_id"; + public const string CONTENT_LIST = "af_content_list"; + public const string CURRENCY = "af_currency"; + public const string QUANTITY = "af_quantity"; + public const string REGSITRATION_METHOD = "af_registration_method"; + public const string PAYMENT_INFO_AVAILIBLE = "af_payment_info_available"; + public const string MAX_RATING_VALUE = "af_max_rating_value"; + public const string RATING_VALUE = "af_rating_value"; + public const string SEARCH_STRING = "af_search_string"; + public const string DATE_A = "af_date_a"; + public const string DATE_B = "af_date_b"; + public const string DESTINATION_A = "af_destination_a"; + public const string DESTINATION_B = "af_destination_b"; + public const string DESCRIPTION = "af_description"; + public const string CLASS = "af_class"; + public const string EVENT_START = "af_event_start"; + public const string EVENT_END = "af_event_end"; + public const string LATITUDE = "af_lat"; + public const string LONGTITUDE = "af_long"; + public const string CUSTOMER_USER_ID = "af_customer_user_id"; + public const string VALIDATED = "af_validated"; + public const string REVENUE = "af_revenue"; + public const string RECEIPT_ID = "af_receipt_id"; + public const string PARAM_1 = "af_param_1"; + public const string PARAM_2 = "af_param_2"; + public const string PARAM_3 = "af_param_3"; + public const string PARAM_4 = "af_param_4"; + public const string PARAM_5 = "af_param_5"; + public const string PARAM_6 = "af_param_6"; + public const string PARAM_7 = "af_param_7"; + public const string PARAM_8 = "af_param_8"; + public const string PARAM_9 = "af_param_9"; + public const string PARAM_10 = "af_param_10"; +} \ No newline at end of file diff --git a/Runtime/AFInAppEvents.cs.meta b/Runtime/AFInAppEvents.cs.meta new file mode 100644 index 0000000..f21eba3 --- /dev/null +++ b/Runtime/AFInAppEvents.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bda50a55ee3549dcb21fc684c4776c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AFMiniJSON.cs b/Runtime/AFMiniJSON.cs new file mode 100644 index 0000000..d02bf2f --- /dev/null +++ b/Runtime/AFMiniJSON.cs @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2013 Calvin Rien + * + * Based on the JSON parser by Patrick van Bergen + * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + * + * Simplified it so that it doesn't throw exceptions + * and can be used in Unity iPhone with maximum code stripping. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace AFMiniJSON { + // Example usage: + // + // using UnityEngine; + // using System.Collections; + // using System.Collections.Generic; + // using MiniJSON; + // + // public class MiniJSONTest : MonoBehaviour { + // void Start () { + // var jsonString = "{ \"array\": [1.44,2,3], " + + // "\"object\": {\"key1\":\"value1\", \"key2\":256}, " + + // "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " + + // "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " + + // "\"int\": 65536, " + + // "\"float\": 3.1415926, " + + // "\"bool\": true, " + + // "\"null\": null }"; + // + // var dict = Json.Deserialize(jsonString) as Dictionary; + // + // Debug.Log("deserialized: " + dict.GetType()); + // Debug.Log("dict['array'][0]: " + ((List) dict["array"])[0]); + // Debug.Log("dict['string']: " + (string) dict["string"]); + // Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles + // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs + // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); + // + // var str = Json.Serialize(dict); + // + // Debug.Log("serialized: " + str); + // } + // } + + /// + /// This class encodes and decodes JSON strings. + /// Spec. details, see http://www.json.org/ + /// + /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. + /// All numbers are parsed to doubles. + /// + public static class Json { + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false + public static object Deserialize(string json) { + // save the string for debug information + if (json == null) { + return null; + } + + return Parser.Parse(json); + } + + sealed class Parser : IDisposable { + const string WORD_BREAK = "{}[],:\""; + + public static bool IsWordBreak(char c) { + return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; + } + + enum TOKEN { + NONE, + CURLY_OPEN, + CURLY_CLOSE, + SQUARED_OPEN, + SQUARED_CLOSE, + COLON, + COMMA, + STRING, + NUMBER, + TRUE, + FALSE, + NULL + }; + + StringReader json; + + Parser(string jsonString) { + json = new StringReader(jsonString); + } + + public static object Parse(string jsonString) { + using (var instance = new Parser(jsonString)) { + return instance.ParseValue(); + } + } + + public void Dispose() { + json.Dispose(); + json = null; + } + + Dictionary ParseObject() { + Dictionary table = new Dictionary(); + + // ditch opening brace + json.Read(); + + // { + while (true) { + switch (NextToken) { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.CURLY_CLOSE: + return table; + default: + // name + string name = ParseString(); + if (name == null) { + return null; + } + + // : + if (NextToken != TOKEN.COLON) { + return null; + } + // ditch the colon + json.Read(); + + // value + table[name] = ParseValue(); + break; + } + } + } + + List ParseArray() { + List array = new List(); + + // ditch opening bracket + json.Read(); + + // [ + var parsing = true; + while (parsing) { + TOKEN nextToken = NextToken; + + switch (nextToken) { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.SQUARED_CLOSE: + parsing = false; + break; + default: + object value = ParseByToken(nextToken); + + array.Add(value); + break; + } + } + + return array; + } + + object ParseValue() { + TOKEN nextToken = NextToken; + return ParseByToken(nextToken); + } + + object ParseByToken(TOKEN token) { + switch (token) { + case TOKEN.STRING: + return ParseString(); + case TOKEN.NUMBER: + return ParseNumber(); + case TOKEN.CURLY_OPEN: + return ParseObject(); + case TOKEN.SQUARED_OPEN: + return ParseArray(); + case TOKEN.TRUE: + return true; + case TOKEN.FALSE: + return false; + case TOKEN.NULL: + return null; + default: + return null; + } + } + + string ParseString() { + StringBuilder s = new StringBuilder(); + char c; + + // ditch opening quote + json.Read(); + + bool parsing = true; + while (parsing) { + + if (json.Peek() == -1) { + parsing = false; + break; + } + + c = NextChar; + switch (c) { + case '"': + parsing = false; + break; + case '\\': + if (json.Peek() == -1) { + parsing = false; + break; + } + + c = NextChar; + switch (c) { + case '"': + case '\\': + case '/': + s.Append(c); + break; + case 'b': + s.Append('\b'); + break; + case 'f': + s.Append('\f'); + break; + case 'n': + s.Append('\n'); + break; + case 'r': + s.Append('\r'); + break; + case 't': + s.Append('\t'); + break; + case 'u': + var hex = new char[4]; + + for (int i=0; i< 4; i++) { + hex[i] = NextChar; + } + + s.Append((char) Convert.ToInt32(new string(hex), 16)); + break; + } + break; + default: + s.Append(c); + break; + } + } + + return s.ToString(); + } + + object ParseNumber() { + string number = NextWord; + + if (number.IndexOf('.') == -1) { + long parsedInt; + Int64.TryParse(number, out parsedInt); + return parsedInt; + } + + double parsedDouble; + Double.TryParse(number, out parsedDouble); + return parsedDouble; + } + + void EatWhitespace() { + while (Char.IsWhiteSpace(PeekChar)) { + json.Read(); + + if (json.Peek() == -1) { + break; + } + } + } + + char PeekChar { + get { + return Convert.ToChar(json.Peek()); + } + } + + char NextChar { + get { + return Convert.ToChar(json.Read()); + } + } + + string NextWord { + get { + StringBuilder word = new StringBuilder(); + + while (!IsWordBreak(PeekChar)) { + word.Append(NextChar); + + if (json.Peek() == -1) { + break; + } + } + + return word.ToString(); + } + } + + TOKEN NextToken { + get { + EatWhitespace(); + + if (json.Peek() == -1) { + return TOKEN.NONE; + } + + switch (PeekChar) { + case '{': + return TOKEN.CURLY_OPEN; + case '}': + json.Read(); + return TOKEN.CURLY_CLOSE; + case '[': + return TOKEN.SQUARED_OPEN; + case ']': + json.Read(); + return TOKEN.SQUARED_CLOSE; + case ',': + json.Read(); + return TOKEN.COMMA; + case '"': + return TOKEN.STRING; + case ':': + return TOKEN.COLON; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN.NUMBER; + } + + switch (NextWord) { + case "false": + return TOKEN.FALSE; + case "true": + return TOKEN.TRUE; + case "null": + return TOKEN.NULL; + } + + return TOKEN.NONE; + } + } + } + + /// + /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string + /// + /// A Dictionary<string, object> / List<object> + /// A JSON encoded string, or null if object 'json' is not serializable + public static string Serialize(object obj) { + return Serializer.Serialize(obj); + } + + sealed class Serializer { + StringBuilder builder; + + Serializer() { + builder = new StringBuilder(); + } + + public static string Serialize(object obj) { + var instance = new Serializer(); + + instance.SerializeValue(obj); + + return instance.builder.ToString(); + } + + void SerializeValue(object value) { + IList asList; + IDictionary asDict; + string asStr; + + if (value == null) { + builder.Append("null"); + } else if ((asStr = value as string) != null) { + SerializeString(asStr); + } else if (value is bool) { + builder.Append((bool) value ? "true" : "false"); + } else if ((asList = value as IList) != null) { + SerializeArray(asList); + } else if ((asDict = value as IDictionary) != null) { + SerializeObject(asDict); + } else if (value is char) { + SerializeString(new string((char) value, 1)); + } else { + SerializeOther(value); + } + } + + void SerializeObject(IDictionary obj) { + bool first = true; + + builder.Append('{'); + + foreach (object e in obj.Keys) { + if (!first) { + builder.Append(','); + } + + SerializeString(e.ToString()); + builder.Append(':'); + + SerializeValue(obj[e]); + + first = false; + } + + builder.Append('}'); + } + + void SerializeArray(IList anArray) { + builder.Append('['); + + bool first = true; + + foreach (object obj in anArray) { + if (!first) { + builder.Append(','); + } + + SerializeValue(obj); + + first = false; + } + + builder.Append(']'); + } + + void SerializeString(string str) { + builder.Append('\"'); + + char[] charArray = str.ToCharArray(); + foreach (var c in charArray) { + switch (c) { + case '"': + builder.Append("\\\""); + break; + case '\\': + builder.Append("\\\\"); + break; + case '\b': + builder.Append("\\b"); + break; + case '\f': + builder.Append("\\f"); + break; + case '\n': + builder.Append("\\n"); + break; + case '\r': + builder.Append("\\r"); + break; + case '\t': + builder.Append("\\t"); + break; + default: + int codepoint = Convert.ToInt32(c); + if ((codepoint >= 32) && (codepoint <= 126)) { + builder.Append(c); + } else { + builder.Append("\\u"); + builder.Append(codepoint.ToString("x4")); + } + break; + } + } + + builder.Append('\"'); + } + + void SerializeOther(object value) { + // NOTE: decimals lose precision during serialization. + // They always have, I'm just letting you know. + // Previously floats and doubles lost precision too. + if (value is float) { + builder.Append(((float) value).ToString("R")); + } else if (value is int + || value is uint + || value is long + || value is sbyte + || value is byte + || value is short + || value is ushort + || value is ulong) { + builder.Append(value); + } else if (value is double + || value is decimal) { + builder.Append(Convert.ToDouble(value).ToString("R")); + } else { + SerializeString(value.ToString()); + } + } + } + } +} diff --git a/Runtime/AFMiniJSON.cs.meta b/Runtime/AFMiniJSON.cs.meta new file mode 100644 index 0000000..55bc8fa --- /dev/null +++ b/Runtime/AFMiniJSON.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54bb2b2c240304b7eaa463b9ff2b1b20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AppsFlyer.cs b/Runtime/AppsFlyer.cs new file mode 100644 index 0000000..af9df81 --- /dev/null +++ b/Runtime/AppsFlyer.cs @@ -0,0 +1,508 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace AppsFlyerSDK +{ + public class AppsFlyer : MonoBehaviour + { + + public static readonly string kAppsFlyerPluginVersion = "5.4.2"; + + + /// + /// Initialize the AppsFlyer SDK with your devKey and appID. + /// The dev key is required on all platforms, and the appID is required for iOS. + /// If you app is for Android only pass null for the appID. + /// + /// AppsFlyer's Dev-Key, which is accessible from your AppsFlyer account under 'App Settings' in the dashboard. + /// Your app's Apple ID. + /// + /// + /// AppsFlyer.initSDK("K2***********99", "41*****44""); + /// + /// + public static void initSDK(string devKey, string appID) + { + initSDK(devKey, appID, null); + } + + /// + /// Initialize the AppsFlyer SDK with your devKey and appID. + /// The dev key is required on all platforms, and the appID is required for iOS. + /// If you app is for Android only pass null for the appID. + /// + /// AppsFlyer's Dev-Key, which is accessible from your AppsFlyer account under 'App Settings' in the dashboard. + /// Your app's Apple ID. + /// pass the script of the game object being used. + /// + /// + /// AppsFlyer.initSDK("K2***********99", 41*****44, this); + /// + /// + public static void initSDK(string devKey, string appID, MonoBehaviour gameObject) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setAppsFlyerDevKey(devKey); + AppsFlyeriOS.setAppleAppID(appID); + if(gameObject != null) + { + AppsFlyeriOS.getConversionData(gameObject.name); + } +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.initSDK(devKey, gameObject); +#else + +#endif + } + + + /// + /// Once this API is invoked, our SDK will start. + /// Once the API is called a sessions will be immediately sent, and all background forground transitions will send a session. + /// + public static void startSDK() + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.startSDK(); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.startSDK(); +#else + +#endif + } + + /// + /// Send an In-App Event. + /// In-App Events provide insight on what is happening in your app. + /// + /// Event Name as String. + /// Event Values as Dictionary. + public static void sendEvent(string eventName, Dictionary eventValues) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.sendEvent(eventName, eventValues); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.sendEvent(eventName, eventValues); +#else + +#endif + } + + /// + /// Once this API is invoked, our SDK no longer communicates with our servers and stops functioning. + /// In some extreme cases you might want to shut down all SDK activity due to legal and privacy compliance. + /// This can be achieved with the stopSDK API. + /// + /// should sdk be stopped. + public static void stopSDK(bool isSDKStopped) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.stopSDK(isSDKStopped); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.stopSDK(isSDKStopped); +#else + +#endif + } + + // + /// Was the stopSDK(boolean) API set to true. + /// + /// boolean isSDKStopped. + public static bool isSDKStopped() + { +#if UNITY_IOS && !UNITY_EDITOR + return AppsFlyeriOS.isSDKStopped(); +#elif UNITY_ANDROID && !UNITY_EDITOR + return AppsFlyerAndroid.isSDKStopped(); +#else + return false; +#endif + } + + /// + /// Get the AppsFlyer SDK version used in app. + /// + /// The current SDK version. + public static string getSdkVersion() + { +#if UNITY_IOS && !UNITY_EDITOR + return AppsFlyeriOS.getSDKVersion(); +#elif UNITY_ANDROID && !UNITY_EDITOR + return AppsFlyerAndroid.getSdkVersion(); +#else + return ""; +#endif + + } + + /// + /// Enables Debug logs for the AppsFlyer SDK. + /// Should only be set to true in development / debug. + /// + /// shouldEnable boolean. + public static void setIsDebug(bool shouldEnable) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setIsDebug(shouldEnable); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setIsDebug(shouldEnable); +#else + +#endif + } + + /// + /// Setting your own customer ID enables you to cross-reference your own unique ID with AppsFlyer’s unique ID and the other devices’ IDs. + /// This ID is available in AppsFlyer CSV reports along with Postback APIs for cross-referencing with your internal IDs. + /// + /// Customer ID for client. + public static void setCustomerUserId(string id) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setCustomerUserID(id); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setCustomerUserId(id); +#else + +#endif + } + + /// + /// Set the OneLink ID that should be used for User-Invite-API. + /// The link that is generated for the user invite will use this OneLink as the base link. + /// + /// OneLink ID obtained from the AppsFlyer Dashboard. + public static void setAppInviteOneLinkID(string oneLinkId) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setAppInviteOneLinkID(oneLinkId); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setAppInviteOneLinkID(oneLinkId); +#else + +#endif + } + + /// + /// Set additional data to be sent to AppsFlyer. + /// + /// additional data Dictionary. + public static void setAdditionalData(Dictionary customData) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setAdditionalData(customData); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setAdditionalData(customData); +#else + +#endif + } + + /// + /// Advertisers can wrap AppsFlyer OneLink within another Universal Link. + /// This Universal Link will invoke the app but any deep linking data will not propagate to AppsFlyer. + /// + /// Array of urls. + public static void setResolveDeepLinkURLs(params string[] urls) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setResolveDeepLinkURLs(urls); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setResolveDeepLinkURLs(urls); +#else + +#endif + } + + + /// + /// Advertisers can use this method to set vanity onelink domains. + /// + /// Array of domains. + public static void setOneLinkCustomDomain(params string[] domains) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setOneLinkCustomDomains(domains); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setOneLinkCustomDomain(domains); +#else + +#endif + } + + /// + /// Setting user local currency code for in-app purchases. + /// The currency code should be a 3 character ISO 4217 code. (default is USD). + /// You can set the currency code for all events by calling the following method. + /// + /// 3 character ISO 4217 code. + public static void setCurrencyCode(string currencyCode) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setCurrencyCode(currencyCode); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setCurrencyCode(currencyCode); +#else + +#endif + } + + /// + /// Manually record the location of the user. + /// + /// latitude as double. + /// longitude as double. + public static void recordLocation(double latitude, double longitude) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.recordLocation(latitude, longitude); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.recordLocation(latitude, longitude); +#else + +#endif + } + + /// + /// Anonymize user Data. + /// Use this API during the SDK Initialization to explicitly anonymize a user's installs, events and sessions. + /// Default is false. + /// + /// shouldAnonymizeUser boolean. + public static void anonymizeUser(bool shouldAnonymizeUser) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.anonymizeUser(shouldAnonymizeUser); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.anonymizeUser(shouldAnonymizeUser); +#else + +#endif + } + + /// + /// Get AppsFlyer's unique device ID which is created for every new install of an app. + /// + /// AppsFlyer's unique device ID. + public static string getAppsFlyerId() + { +#if UNITY_IOS && !UNITY_EDITOR + return AppsFlyeriOS.getAppsFlyerId(); +#elif UNITY_ANDROID && !UNITY_EDITOR + return AppsFlyerAndroid.getAppsFlyerId(); +#else + return ""; +#endif + + } + + /// + /// Set a custom value for the minimum required time between sessions. + /// By default, at least 5 seconds must lapse between 2 app launches to count as separate 2 sessions. + /// + /// minimum time between 2 separate sessions in seconds. + public static void setMinTimeBetweenSessions(int seconds) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setMinTimeBetweenSessions(seconds); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setMinTimeBetweenSessions(seconds); +#else + +#endif + } + + /// + /// Set a custom host. + /// + /// Host prefix. + /// Host name. + public static void setHost(string hostPrefixName, string hostName) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setHost(hostName, hostPrefixName); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setHost(hostPrefixName, hostName); +#else + +#endif + } + + /// + /// Set the user emails and encrypt them. + /// cryptMethod Encryption method: + /// EmailCryptType.EmailCryptTypeMD5 + /// EmailCryptType.EmailCryptTypeSHA1 + /// EmailCryptType.EmailCryptTypeSHA256 + /// EmailCryptType.EmailCryptTypeNone + /// + /// Encryption method. + /// User emails. + public static void setUserEmails(EmailCryptType cryptMethod, params string[] emails) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setUserEmails(cryptMethod, emails.Length, emails); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setUserEmails(cryptMethod, emails); +#else + +#endif + } + + /// + /// Set the user phone number. + /// + /// phoneNumber string + public static void setPhoneNumber(string phoneNumber) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setPhoneNumber(phoneNumber); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setPhoneNumber(phoneNumber); +#else + +#endif + } + + /// + /// Used by advertisers to exclude all networks/integrated partners from getting data. + /// + public static void setSharingFilterForAllPartners() + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setSharingFilterForAllPartners(); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setSharingFilterForAllPartners(); +#else + +#endif + } + + /// + /// Used by advertisers to set some (one or more) networks/integrated partners to exclude from getting data. + /// + /// partners to exclude from getting data + public static void setSharingFilter(params string[] partners) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.setSharingFilter(partners); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.setSharingFilter(partners); +#else + +#endif + } + + /// + /// Register a Conversion Data Listener. + /// Allows the developer to access the user attribution data in real-time for every new install, directly from the SDK level. + /// By doing this you can serve users with personalized content or send them to specific activities within the app, + /// which can greatly enhance their engagement with your app. + /// + /// + /// + /// AppsFlyer.getConversionData(this.name); + /// + /// + public static void getConversionData(string objectName) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.getConversionData(objectName); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.getConversionData(objectName); +#else + +#endif + } + + + /// + /// Use the following API to attribute the click and launch the app store's app page. + /// + /// promoted App ID + /// cross promotion campaign + /// additional user params + /// + /// + /// Dictionary parameters = new Dictionary(); + /// parameters.Add("af_sub1", "val"); + /// parameters.Add("custom_param", "val2"); + /// AppsFlyer.attributeAndOpenStore("123456789", "test campaign", parameters, this); + /// + /// + public static void attributeAndOpenStore(string appID, string campaign, Dictionary userParams, MonoBehaviour gameObject) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.attributeAndOpenStore(appID, campaign, userParams, gameObject); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.attributeAndOpenStore(appID, campaign, userParams); +#else + +#endif + } + + /// + /// To attribute an impression use the following API call. + /// Make sure to use the promoted App ID as it appears within the AppsFlyer dashboard. + /// + /// promoted App ID. + /// cross promotion campaign. + /// parameters Dictionary. + public static void recordCrossPromoteImpression(string appID, string campaign, Dictionary parameters) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.recordCrossPromoteImpression(appID, campaign, parameters); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.recordCrossPromoteImpression(appID, campaign, parameters); +#else + +#endif + } + + /// + /// The LinkGenerator class builds the invite URL according to various setter methods which allow passing on additional information on the click. + /// See - https://support.appsflyer.com/hc/en-us/articles/115004480866-User-invite-attribution- + /// + /// parameters Dictionary. + public static void generateUserInviteLink(Dictionary parameters, MonoBehaviour gameObject) + { +#if UNITY_IOS && !UNITY_EDITOR + AppsFlyeriOS.generateUserInviteLink(parameters, gameObject); +#elif UNITY_ANDROID && !UNITY_EDITOR + AppsFlyerAndroid.generateUserInviteLink(parameters, gameObject); +#else + +#endif + } + + /// + /// Helper method to convert json strings to dictionary. + /// + /// json string + /// dictionary representing the input json string. + public static Dictionary CallbackStringToDictionary(string str) + { + return AFMiniJSON.Json.Deserialize(str) as Dictionary; + } + + /// + /// Helper method to log AppsFlyer events and callbacks. + /// + /// method name + /// message to log + public static void AFLog(string methodName, string str) + { + Debug.Log(string.Format("AppsFlyer_Unity_v{0} {1} called with {2}", kAppsFlyerPluginVersion, methodName, str)); + } + } + + public enum EmailCryptType + { + // None + EmailCryptTypeNone = 0, + // SHA256 + EmailCryptTypeSHA256 = 1, + } + +} \ No newline at end of file diff --git a/Runtime/AppsFlyer.cs.meta b/Runtime/AppsFlyer.cs.meta new file mode 100644 index 0000000..a7e4587 --- /dev/null +++ b/Runtime/AppsFlyer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ee67b96679174324b71b44080a6741c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AppsFlyerAndroid.cs b/Runtime/AppsFlyerAndroid.cs new file mode 100644 index 0000000..2ce7d61 --- /dev/null +++ b/Runtime/AppsFlyerAndroid.cs @@ -0,0 +1,657 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AppsFlyerSDK +{ + +#if UNITY_ANDROID + public class AppsFlyerAndroid + { + + private static AndroidJavaClass appsFlyerAndroid = new AndroidJavaClass("com.appsflyer.unity.AppsFlyerAndroidWrapper"); + + + /// + /// Use this method to init the sdk for the application. + /// Call this method before startSDK. + /// + /// AppsFlyer's Dev-Key, which is accessible from your AppsFlyer account under 'App Settings' in the dashboard. + /// The current game object. This is used to get the conversion data callbacks. Pass null if you do not need the callbacks. + public static void initSDK(string devkey, MonoBehaviour gameObject) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("initSDK", devkey, gameObject ? gameObject.name : null); +#endif + } + + /// + /// Use this method to start the sdk for the application. + /// The AppsFlyer's Dev-Key must be provided. + /// + /// AppsFlyer's Dev-Key, which is accessible from your AppsFlyer account under 'App Settings' in the dashboard. + public static void startSDK() + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("startTracking"); +#endif + } + + /// + /// Once this API is invoked, our SDK no longer communicates with our servers and stops functioning. + /// In some extreme cases you might want to shut down all SDK activity due to legal and privacy compliance. + /// This can be achieved with the stopSDK API. + /// + /// boolean should SDK be stopped. + public static void stopSDK(bool isSDKStopped) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("stopTracking", isSDKStopped); +#endif + } + + /// + /// Get the AppsFlyer SDK version used in app. + /// + /// AppsFlyer SDK version. + public static string getSdkVersion() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("getSdkVersion"); +#else + return ""; +#endif + } + + /// + /// Manually pass the Firebase / GCM Device Token for Uninstall measurement. + /// + /// Firebase Device Token. + public static void updateServerUninstallToken(string token) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("updateServerUninstallToken", token); +#endif + } + + /// + /// Enables Debug logs for the AppsFlyer SDK. + /// Should only be set to true in development / debug. + /// + /// shouldEnable boolean. + public static void setIsDebug(bool shouldEnable) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setIsDebug", shouldEnable); +#endif + } + + /// + /// By default, IMEI and Android ID are not collected by the SDK if the OS version is higher than KitKat (4.4) + /// and the device contains Google Play Services(on SDK versions 4.8.8 and below the specific app needed GPS). + /// Use this API to explicitly send IMEI to AppsFlyer. + /// + /// device's IMEI. + public static void setImeiData(string aImei) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setImeiData", aImei); +#endif + } + + /// + /// By default, IMEI and Android ID are not collected by the SDK if the OS version is higher than KitKat(4.4) + /// and the device contains Google Play Services(on SDK versions 4.8.8 and below the specific app needed GPS). + /// Use this API to explicitly send Android ID to AppsFlyer. + /// + /// device's Android ID. + public static void setAndroidIdData(string aAndroidId) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setAndroidIdData", aAndroidId); +#endif + } + + /// + /// Setting your own customer ID enables you to cross-reference your own unique ID with AppsFlyer’s unique ID and the other devices’ IDs. + /// This ID is available in AppsFlyer CSV reports along with Postback APIs for cross-referencing with your internal IDs. + /// + /// Customer ID for client. + public static void setCustomerUserId(string id) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setCustomerUserId", id); +#endif + } + + /// + /// It is possible to delay the SDK Initialization until the customerUserID is set. + /// This feature makes sure that the SDK doesn't begin functioning until the customerUserID is provided. + /// If this API is used, all in-app events and any other SDK API calls are discarded, until the customerUserID is provided. + /// + /// wait boolean. + public static void waitForCustomerUserId(bool wait) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("waitForCustomerUserId", wait); +#endif + } + + /// + /// Use this API to provide the SDK with the relevant customer user id and trigger the SDK to begin its normal activity. + /// + /// Customer ID for client. + public static void setCustomerIdAndStartSDK(string id) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setCustomerIdAndTrack", id); +#endif + } + + /// + /// Get the current AF_STORE value. + /// + /// AF_Store value. + public static string getOutOfStore() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("getOutOfStore"); +#else + return ""; +#endif + } + + /// + /// Manually set the AF_STORE value. + /// + /// value to be set. + public static void setOutOfStore(string sourceName) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setOutOfStore", sourceName); +#endif + } + + /// + /// Set the OneLink ID that should be used for User-Invites. + /// The link that is generated for the user invite will use this OneLink as the base link. + /// + /// OneLink ID obtained from the AppsFlyer Dashboard. + public static void setAppInviteOneLinkID(string oneLinkId) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setAppInviteOneLinkID", oneLinkId); +#endif + } + + /// + /// Set additional data to be sent to AppsFlyer. + /// + /// additional data Dictionary. + public static void setAdditionalData(Dictionary customData) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setAdditionalData", convertDictionaryToJavaMap(customData)); +#endif + } + + /// + /// Set the user emails. + /// + /// User emails. + public static void setUserEmails(params string[] emails) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setUserEmails", (object)emails); +#endif + } + + + /// + /// Set the user phone number. + /// + /// User phoneNumber. + public static void setPhoneNumber(string phoneNumber){ +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setPhoneNumber", phoneNumber); +#endif + } + + /// + /// Set the user emails and encrypt them. + /// cryptMethod Encryption method: + /// EmailCryptType.EmailCryptTypeMD5 + /// EmailCryptType.EmailCryptTypeSHA1 + /// EmailCryptType.EmailCryptTypeSHA256 + /// EmailCryptType.EmailCryptTypeNone + /// + /// Encryption method. + /// User emails. + public static void setUserEmails(EmailCryptType cryptMethod, params string[] emails) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setUserEmails", getEmailType(cryptMethod), (object)emails); +#endif + } + + /// + /// Opt-out of collection of Android ID. + /// If the app does NOT contain Google Play Services, Android ID is collected by the SDK. + /// However, apps with Google play services should avoid Android ID collection as this is in violation of the Google Play policy. + /// + /// boolean, false to opt-out. + public static void setCollectAndroidID(bool isCollect) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setCollectAndroidID", isCollect); +#endif + } + + /// + /// Opt-out of collection of IMEI. + /// If the app does NOT contain Google Play Services, device IMEI is collected by the SDK. + /// However, apps with Google play services should avoid IMEI collection as this is in violation of the Google Play policy. + /// + /// boolean, false to opt-out. + public static void setCollectIMEI(bool isCollect) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setCollectIMEI", isCollect); +#endif + } + + /// + /// Advertisers can wrap AppsFlyer OneLink within another Universal Link. + /// This Universal Link will invoke the app but any deep linking data will not propagate to AppsFlyer. + /// + /// Array of urls. + public static void setResolveDeepLinkURLs(params string[] urls) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setResolveDeepLinkURLs", (object)urls); +#endif + } + + + /// + /// Advertisers can use this method to set vanity onelink domains. + /// + /// Array of domains. + public static void setOneLinkCustomDomain(params string[] domains) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setOneLinkCustomDomain", (object)domains); +#endif + } + + /// + /// Manually set that the application was updated. + /// + /// isUpdate boolean value. + public static void setIsUpdate(bool isUpdate) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setIsUpdate", isUpdate); +#endif + } + + /// + /// Setting user local currency code for in-app purchases. + /// The currency code should be a 3 character ISO 4217 code. (default is USD). + /// You can set the currency code for all events by calling the following method. + /// + /// 3 character ISO 4217 code. + public static void setCurrencyCode(string currencyCode) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setCurrencyCode", currencyCode); +#endif + } + + /// + /// Manually record the location of the user. + /// + /// latitude as double. + /// longitude as double. + public static void recordLocation(double latitude, double longitude) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("trackLocation", latitude, longitude); +#endif + } + + /// + /// Send an In-App Event. + /// In-App Events provide insight on what is happening in your app. + /// + /// Event Name as String. + /// Event Values as Dictionary. + public static void sendEvent(string eventName, Dictionary eventValues) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("trackEvent", eventName, convertDictionaryToJavaMap(eventValues)); +#endif + } + + /// + /// Anonymize user Data. + /// Use this API during the SDK Initialization to explicitly anonymize a user's installs, events and sessions. + /// Default is false. + /// + /// isDisabled boolean. + public static void anonymizeUser(bool isDisabled) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setDeviceTrackingDisabled", isDisabled); +#endif + } + + /// + /// Enable the collection of Facebook Deferred AppLinks. + /// Requires Facebook SDK and Facebook app on target/client device. + /// This API must be invoked prior to initializing the AppsFlyer SDK in order to function properly. + /// + /// should Facebook's deferred app links be processed by the AppsFlyer SDK. + public static void enableFacebookDeferredApplinks(bool isEnabled) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("enableFacebookDeferredApplinks", isEnabled); +#endif + } + + + /// + /// Restrict reengagement via deep-link to once per each unique deep-link. + /// Otherwise deep re-occurring deep-links will be permitted for non-singleTask Activities and deep-linking via AppsFlyer deep-links. + /// The default value is false. + /// + /// doConsume boolean. + public static void setConsumeAFDeepLinks(bool doConsume) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setConsumeAFDeepLinks", doConsume); +#endif + } + + /// + /// Specify the manufacturer or media source name to which the preinstall is attributed. + /// + /// Manufacturer or media source name for preinstall attribution. + /// Campaign name for preinstall attribution. + /// Site ID for preinstall attribution. + public static void setPreinstallAttribution(string mediaSource, string campaign, string siteId) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setPreinstallAttribution", mediaSource, campaign, siteId); +#endif + } + + /// + /// Boolean indicator for preinstall by Manufacturer. + /// + /// boolean isPreInstalledApp. + public static bool isPreInstalledApp() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("isPreInstalledApp"); +#else + return false; +#endif + } + + /// + /// Get the Facebook attribution ID, if one exists. + /// + /// string Facebook attribution ID. + public static string getAttributionId() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("getAttributionId"); +#else + return ""; +#endif + } + + /// + /// Get AppsFlyer's unique device ID is created for every new install of an app. + /// + /// AppsFlyer's unique device ID. + public static string getAppsFlyerId() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("getAppsFlyerId"); +#else + return ""; +#endif + } + + /// + /// API for server verification of in-app purchases. + /// An af_purchase event with the relevant values will be automatically sent if the validation is successful. + /// + /// License Key obtained from the Google Play Console. + /// data.INAPP_DATA_SIGNATURE from onActivityResult(int requestCode, int resultCode, Intent data) + /// data.INAPP_PURCHASE_DATA from onActivityResult(int requestCode, int resultCode, Intent data) + /// Purchase price, should be derived from skuDetails.getStringArrayList("DETAILS_LIST") + /// Purchase currency, should be derived from skuDetails.getStringArrayList("DETAILS_LIST") + /// additionalParameters Freehand parameters to be sent with the purchase (if validated). + public static void validateAndSendInAppPurchase(string publicKey, string signature, string purchaseData, string price, string currency, Dictionary additionalParameters, MonoBehaviour gameObject) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("validateAndTrackInAppPurchase", publicKey, signature, purchaseData, price, currency, convertDictionaryToJavaMap(additionalParameters), gameObject ? gameObject.name : null); +#endif + } + + /// + /// Was the stopSDK(boolean) API set to true. + /// + /// boolean isSDKStopped. + public static bool isSDKStopped() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("isTrackingStopped"); +#else + return false; +#endif + } + + /// + /// Set a custom value for the minimum required time between sessions. + /// By default, at least 5 seconds must lapse between 2 app launches to count as separate 2 sessions. + /// + /// minimum time between 2 separate sessions in seconds. + public static void setMinTimeBetweenSessions(int seconds) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setMinTimeBetweenSessions", seconds); +#endif + } + + /// + /// Set a custom host. + /// + /// Host prefix. + /// Host name. + public static void setHost(string hostPrefixName, string hostName) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setHost", hostPrefixName, hostName); +#endif + } + + /// + /// Get the host name. + /// Default value is "appsflyer.com". + /// + /// Host name. + public static string getHostName() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("getHostName"); +#else + return ""; +#endif + } + + /// + /// Get the custom host prefix. + /// + /// Host prefix. + public static string getHostPrefix() + { +#if !UNITY_EDITOR + return appsFlyerAndroid.CallStatic("getHostPrefix"); +#else + return ""; +#endif + } + + /// + /// Used by advertisers to exclude all networks/integrated partners from getting data. + /// + public static void setSharingFilterForAllPartners() + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setSharingFilterForAllPartners"); +#endif + } + + /// + /// Used by advertisers to set some (one or more) networks/integrated partners to exclude from getting data. + /// + /// partners to exclude from getting data + public static void setSharingFilter(params string[] partners) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setSharingFilter", (object)partners); +#endif + } + + /// + /// Register a Conversion Data Listener. + /// Allows the developer to access the user attribution data in real-time for every new install, directly from the SDK level. + /// By doing this you can serve users with personalized content or send them to specific activities within the app, + /// which can greatly enhance their engagement with your app. + /// + public static void getConversionData(string objectName) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("getConversionData", objectName); +#endif + } + + /// + /// Register a validation listener for the validateAndSendInAppPurchase API. + /// + public static void initInAppPurchaseValidatorListener(MonoBehaviour gameObject) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("initInAppPurchaseValidatorListener", gameObject ? gameObject.name : null); +#endif + } + + /// + /// setCollectOaid + /// You must include the appsflyer oaid library for this api to work. + /// + /// isCollect oaid - set fasle to opt out + public static void setCollectOaid(bool isCollect) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("setCollectOaid", isCollect); +#endif + } + + /// + /// Use the following API to attribute the click and launch the app store's app page. + /// + /// promoted App ID + /// cross promotion campaign + /// additional user params + public static void attributeAndOpenStore(string promoted_app_id, string campaign, Dictionary userParams) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("attributeAndOpenStore", promoted_app_id, campaign, convertDictionaryToJavaMap(userParams)); +#endif + } + + /// + /// To attribute an impression use the following API call. + /// Make sure to use the promoted App ID as it appears within the AppsFlyer dashboard. + /// + /// promoted App ID. + /// cross promotion campaign. + /// parameters Dictionary. + public static void recordCrossPromoteImpression(string appID, string campaign, Dictionary parameters) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("recordCrossPromoteImpression", appID, campaign, convertDictionaryToJavaMap(parameters)); +#endif + } + + /// + /// The LinkGenerator class builds the invite URL according to various setter methods which allow passing on additional information on the click. + /// See - https://support.appsflyer.com/hc/en-us/articles/115004480866-User-invite-attribution- + /// + /// parameters Dictionary. + public static void generateUserInviteLink(Dictionary parameters, MonoBehaviour gameObject) + { +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("createOneLinkInviteListener", convertDictionaryToJavaMap(parameters), gameObject ? gameObject.name : null); +#endif + } + + /// + /// To measure push notifications as part of a retargeting campaign. + /// + public static void handlePushNotifications(){ +#if !UNITY_EDITOR + appsFlyerAndroid.CallStatic("handlePushNotifications"); +#endif + } + + /// + /// Internal Helper Method. + /// + private static AndroidJavaObject getEmailType(EmailCryptType cryptType) + { + AndroidJavaClass emailsCryptTypeEnum = new AndroidJavaClass("com.appsflyer.AppsFlyerProperties$EmailsCryptType"); + AndroidJavaObject emailsCryptType; + + switch (cryptType) + { + case EmailCryptType.EmailCryptTypeSHA256: + emailsCryptType = emailsCryptTypeEnum.GetStatic("SHA256"); + break; + default: + emailsCryptType = emailsCryptTypeEnum.GetStatic("NONE"); + break; + } + + return emailsCryptType; + } + + /// + /// Internal Helper Method. + /// + private static AndroidJavaObject convertDictionaryToJavaMap(Dictionary dictionary) + { + AndroidJavaObject map = new AndroidJavaObject("java.util.HashMap"); + IntPtr putMethod = AndroidJNIHelper.GetMethodID(map.GetRawClass(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + if (dictionary != null) + { + foreach (var entry in dictionary) + { + AndroidJNI.CallObjectMethod(map.GetRawObject(), putMethod, AndroidJNIHelper.CreateJNIArgArray(new object[] { entry.Key, entry.Value })); + } + } + + return map; + } + } + +#endif + + + +} \ No newline at end of file diff --git a/Runtime/AppsFlyerAndroid.cs.meta b/Runtime/AppsFlyerAndroid.cs.meta new file mode 100644 index 0000000..ca999f3 --- /dev/null +++ b/Runtime/AppsFlyerAndroid.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1acf06d8f799e4050b792abc42365ab8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AppsFlyerObject.prefab b/Runtime/AppsFlyerObject.prefab new file mode 100644 index 0000000..6c9e085 --- /dev/null +++ b/Runtime/AppsFlyerObject.prefab @@ -0,0 +1,57 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 0} + m_RootGameObject: {fileID: 1562408896289314} + m_IsPrefabAsset: 1 +--- !u!1 &1562408896289314 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 6 + m_Component: + - component: {fileID: 4294345628247858} + - component: {fileID: 114092076686766906} + m_Layer: 0 + m_Name: AppsFlyerObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4294345628247858 +Transform: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1562408896289314} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &114092076686766906 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1562408896289314} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2caf6a738ac024a48bd358f4cc91662a, type: 3} + m_Name: + m_EditorClassIdentifier: + devKey: + appID: + isDebug: 0 + getConversionData: 0 diff --git a/Runtime/AppsFlyerObject.prefab.meta b/Runtime/AppsFlyerObject.prefab.meta new file mode 100644 index 0000000..ddaed06 --- /dev/null +++ b/Runtime/AppsFlyerObject.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4a0acc9a317ee4b6191c57e81b0ddfb7 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AppsFlyerObjectScript.cs b/Runtime/AppsFlyerObjectScript.cs new file mode 100644 index 0000000..49b7b48 --- /dev/null +++ b/Runtime/AppsFlyerObjectScript.cs @@ -0,0 +1,59 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using AppsFlyerSDK; + +// This class is intended to be used the the AppsFlyerObject.prefab + +public class AppsFlyerObjectScript : MonoBehaviour , IAppsFlyerConversionData +{ + + // These fields are set from the editor so do not modify! + //******************************// + public string devKey; + public string appID; + public bool isDebug; + public bool getConversionData; + //******************************// + + void Start() + { + // These fields are set from the editor so do not modify! + //******************************// + AppsFlyer.setIsDebug(isDebug); + AppsFlyer.initSDK(devKey, appID, getConversionData ? this : null); + //******************************// + + AppsFlyer.startSDK(); + } + + void Update() + { + + } + + // Mark AppsFlyer CallBacks + public void onConversionDataSuccess(string conversionData) + { + AppsFlyer.AFLog("didReceiveConversionData", conversionData); + Dictionary conversionDataDictionary = AppsFlyer.CallbackStringToDictionary(conversionData); + // add deferred deeplink logic here + } + + public void onConversionDataFail(string error) + { + AppsFlyer.AFLog("didReceiveConversionDataWithError", error); + } + + public void onAppOpenAttribution(string attributionData) + { + AppsFlyer.AFLog("onAppOpenAttribution", attributionData); + Dictionary attributionDataDictionary = AppsFlyer.CallbackStringToDictionary(attributionData); + // add direct deeplink logic here + } + + public void onAppOpenAttributionFailure(string error) + { + AppsFlyer.AFLog("onAppOpenAttributionFailure", error); + } +} diff --git a/Runtime/AppsFlyerObjectScript.cs.meta b/Runtime/AppsFlyerObjectScript.cs.meta new file mode 100644 index 0000000..25ee3d5 --- /dev/null +++ b/Runtime/AppsFlyerObjectScript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2caf6a738ac024a48bd358f4cc91662a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/AppsFlyeriOS.cs b/Runtime/AppsFlyeriOS.cs new file mode 100644 index 0000000..7992153 --- /dev/null +++ b/Runtime/AppsFlyeriOS.cs @@ -0,0 +1,586 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace AppsFlyerSDK +{ +#if UNITY_IOS + + public class AppsFlyeriOS + { + + /// + /// Start Session. + /// This will record a session and then record all background forground sessions during the lifecycle of the app. + /// + public static void startSDK() + { +#if !UNITY_EDITOR + _startSDK(); +#endif + } + + /// + /// Send an In-App Event. + /// In-App Events provide insight on what is happening in your app. + /// + /// Name of event. + /// Contains dictionary of values for handling by backend. + public static void sendEvent(string eventName, Dictionary eventValues) + { +#if !UNITY_EDITOR + _afSendEvent(eventName, AFMiniJSON.Json.Serialize(eventValues)); +#endif + } + + /// + /// Get the conversion data. + /// Allows the developer to access the user attribution data in real-time for every new install, directly from the SDK level. + /// By doing this you can serve users with personalized content or send them to specific activities within the app, + /// which can greatly enhance their engagement with your app. + /// + public static void getConversionData(string objectName) + { +#if !UNITY_EDITOR + _getConversionData(objectName); +#endif + } + + /// + /// In case you use your own user ID in your app, you can set this property to that ID. + /// Enables you to cross-reference your own unique ID with AppsFlyer’s unique ID and the other devices’ IDs. + /// + /// Customer ID for client. + public static void setCustomerUserID(string customerUserID) + { +#if !UNITY_EDITOR + _setCustomerUserID(customerUserID); +#endif + } + + /// + /// In case you use custom data and you want to receive it in the raw reports. + /// see [Setting additional custom data] (https://support.appsflyer.com/hc/en-us/articles/207032066-AppsFlyer-SDK-Integration-iOS#setting-additional-custom-data) for more information. + /// + /// additional data Dictionary. + public static void setAdditionalData(Dictionary customData) + { +#if !UNITY_EDITOR + _setAdditionalData(AFMiniJSON.Json.Serialize(customData)); +#endif + } + + /// + /// Use this method to set your AppsFlyer's dev key. + /// + /// AppsFlyer's Dev-Key, which is accessible from your AppsFlyer account under 'App Settings' in the dashboard. + public static void setAppsFlyerDevKey(string appsFlyerDevKey) + { +#if !UNITY_EDITOR + _setAppsFlyerDevKey(appsFlyerDevKey); +#endif + } + + /// + /// Use this method to set your app's Apple ID(taken from the app's page on iTunes Connect). + /// + /// your app's Apple ID. + public static void setAppleAppID(string appleAppID) + { +#if !UNITY_EDITOR + _setAppleAppID(appleAppID); +#endif + } + + /// + /// Setting user local currency code for in-app purchases. + /// The currency code should be a 3 character ISO 4217 code. (default is USD). + /// You can set the currency code for all events by calling the following method. + /// + /// 3 character ISO 4217 code. + public static void setCurrencyCode(string currencyCode) + { +#if !UNITY_EDITOR + _setCurrencyCode(currencyCode); +#endif + } + + /// + /// AppsFlyer SDK collect Apple's `advertisingIdentifier` if the `AdSupport.framework` included in the SDK. + /// You can disable this behavior by setting the following property to true. + /// + /// boolean to disableCollectAppleAdSupport + public static void setDisableCollectAppleAdSupport(bool disableCollectAppleAdSupport) + { +#if !UNITY_EDITOR + _setDisableCollectAppleAdSupport(disableCollectAppleAdSupport); +#endif + } + + /// + /// Enables Debug logs for the AppsFlyer SDK. + /// Should only be set to true in development / debug. + /// The default value is false. + /// + /// shouldEnable boolean.. + public static void setIsDebug(bool isDebug) + { +#if !UNITY_EDITOR + _setIsDebug(isDebug); +#endif + } + + /// + /// Set this flag to true, to collect the current device name(e.g. "My iPhone"). Default value is false. + /// + /// boolean shouldCollectDeviceName. + public static void setShouldCollectDeviceName(bool shouldCollectDeviceName) + { +#if !UNITY_EDITOR + _setShouldCollectDeviceName(shouldCollectDeviceName); +#endif + } + + /// + /// Set the OneLink ID that should be used for User-Invites. + /// The link that is generated for the user invite will use this OneLink as the base link. + /// + /// OneLink ID obtained from the AppsFlyer Dashboard. + public static void setAppInviteOneLinkID(string appInviteOneLinkID) + { +#if !UNITY_EDITOR + _setAppInviteOneLinkID(appInviteOneLinkID); +#endif + } + + /// + /// Anonymize user Data. + /// Use this API during the SDK Initialization to explicitly anonymize a user's installs, events and sessions. + /// Default is false + /// + /// boolean shouldAnonymizeUser. + public static void anonymizeUser(bool shouldAnonymizeUser) + { +#if !UNITY_EDITOR + _anonymizeUser(shouldAnonymizeUser); +#endif + } + + /// + /// Opt-out for Apple Search Ads attributions. + /// + /// boolean disableCollectIAd. + public static void setDisableCollectIAd(bool disableCollectIAd) + { +#if !UNITY_EDITOR + _setDisableCollectIAd(disableCollectIAd); +#endif + } + + /// + /// In app purchase receipt validation Apple environment(production or sandbox). The default value is false. + /// + /// boolean useReceiptValidationSandbox. + public static void setUseReceiptValidationSandbox(bool useReceiptValidationSandbox) + { +#if !UNITY_EDITOR + _setUseReceiptValidationSandbox(useReceiptValidationSandbox); +#endif + } + + /// + /// Set this flag to test uninstall on Apple environment(production or sandbox). The default value is false. + /// + /// boolean useUninstallSandbox. + public static void setUseUninstallSandbox(bool useUninstallSandbox) + { +#if !UNITY_EDITOR + _setUseUninstallSandbox(useUninstallSandbox); +#endif + } + + /// + /// For advertisers who wrap OneLink within another Universal Link. + /// An advertiser will be able to deeplink from a OneLink wrapped within another Universal Link and also record this retargeting conversion. + /// + /// Array of urls. + public static void setResolveDeepLinkURLs(params string[] resolveDeepLinkURLs) + { +#if !UNITY_EDITOR + _setResolveDeepLinkURLs(resolveDeepLinkURLs.Length,resolveDeepLinkURLs); +#endif + } + + /// + /// For advertisers who use vanity OneLinks. + /// + /// Array of domains. + public static void setOneLinkCustomDomains(params string[] oneLinkCustomDomains) + { +#if !UNITY_EDITOR + _setOneLinkCustomDomains(oneLinkCustomDomains.Length, oneLinkCustomDomains); +#endif + } + + /// + /// Set the user emails and encrypt them. + /// cryptMethod Encryption method: + /// EmailCryptType.EmailCryptTypeMD5 + /// EmailCryptType.EmailCryptTypeSHA1 + /// EmailCryptType.EmailCryptTypeSHA256 + /// EmailCryptType.EmailCryptTypeNone + /// + /// type Hash algoritm. + /// length of userEmails array. + /// userEmails The list of strings that hold mails. + public static void setUserEmails(EmailCryptType cryptType, int length, params string[] userEmails) + { +#if !UNITY_EDITOR + _setUserEmails(cryptType, length, userEmails); +#endif + } + + /// + /// Set the user phone number. + /// + /// User phoneNumber. + public static void setPhoneNumber(string phoneNumber){ +#if !UNITY_EDITOR + _setPhoneNumber(phoneNumber); +#endif + } + + /// + /// To send and validate in app purchases you can call this method from the processPurchase method. + /// + /// The product identifier. + /// The product price. + /// The product currency. + /// The purchase transaction Id. + /// The additional param, which you want to receive it in the raw reports. + public static void validateAndSendInAppPurchase(string productIdentifier, string price, string currency, string tranactionId, Dictionary additionalParameters, MonoBehaviour gameObject) + { +#if !UNITY_EDITOR + _validateAndSendInAppPurchase(productIdentifier, price, currency, tranactionId, AFMiniJSON.Json.Serialize(additionalParameters), gameObject ? gameObject.name : null); +#endif + } + + /// + /// To record location for geo-fencing. Does the same as code below. + /// + /// The location longitude. + /// The location latitude. + public static void recordLocation(double longitude, double latitude) + { +#if !UNITY_EDITOR + _recordLocation(longitude, latitude); +#endif + } + + /// + /// Get AppsFlyer's unique device ID, which is created for every new install of an app. + /// + public static string getAppsFlyerId() + { +#if !UNITY_EDITOR + return _getAppsFlyerId(); +#else + return ""; +#endif + } + + /// + /// Register uninstall - you should register for remote notification and provide AppsFlyer the push device token. + /// + /// deviceToken The `deviceToken` from `-application:didRegisterForRemoteNotificationsWithDeviceToken:`. + public static void registerUninstall(byte[] deviceToken) + { +#if !UNITY_EDITOR + _registerUninstall(deviceToken); +#endif + } + + /// + /// Enable AppsFlyer to handle a push notification. + /// + /// pushPayload The `userInfo` from received remote notification. One of root keys should be @"af".. + public static void handlePushNotification(Dictionary pushPayload) + { +#if !UNITY_EDITOR + _handlePushNotification(AFMiniJSON.Json.Serialize(pushPayload)); +#endif + } + + /// + /// Get SDK version. + /// + public static string getSDKVersion() + { +#if !UNITY_EDITOR + return _getSDKVersion(); +#else + return ""; +#endif + } + + /// + /// This property accepts a string value representing the host name for all endpoints. + /// Can be used to Zero rate your application’s data usage.Contact your CSM for more information. + /// + /// Host Name. + /// Host prefix. + public static void setHost(string host, string hostPrefix) + { +#if !UNITY_EDITOR + _setHost(host, hostPrefix); +#endif + } + + /// + /// This property is responsible for timeout between sessions in seconds. + /// Default value is 5 seconds. + /// + /// minimum time between 2 separate sessions in seconds. + public static void setMinTimeBetweenSessions(int minTimeBetweenSessions) + { +#if !UNITY_EDITOR + _setMinTimeBetweenSessions(minTimeBetweenSessions); +#endif + } + + /// + /// Once this API is invoked, our SDK no longer communicates with our servers and stops functioning. + /// In some extreme cases you might want to shut down all SDK activity due to legal and privacy compliance. + /// This can be achieved with the stopSDK API. + /// + /// boolean isSDKStopped. + public static void stopSDK(bool isSDKStopped) + { +#if !UNITY_EDITOR + _stopSDK(isSDKStopped); +#endif + } + + // + /// Was the stopSDK(boolean) API set to true. + /// + /// boolean isSDKStopped. + public static bool isSDKStopped() + { +#if !UNITY_EDITOR + return _isSDKStopped(); +#else + return false; +#endif + } + + /// + /// In case you want to track deep linking manually call handleOpenUrl. + /// The continueUserActivity and onOpenURL are implemented in the AppsFlyerAppController.mm class, so + /// only use this method if the other methods do not cover your apps deeplinking needs. + /// + /// The URL to be passed to your AppDelegate. + /// The sourceApplication to be passed to your AppDelegate. + /// The annotation to be passed to your app delegate. + public static void handleOpenUrl(string url, string sourceApplication, string annotation) + { +#if !UNITY_EDITOR + _handleOpenUrl(url, sourceApplication, annotation); +#endif + } + + /// + /// Used by advertisers to exclude all networks/integrated partners from getting data. + /// + public static void setSharingFilterForAllPartners() + { +#if !UNITY_EDITOR + _setSharingFilterForAllPartners(); +#endif + } + + /// + /// Used by advertisers to set some (one or more) networks/integrated partners to exclude from getting data. + /// + /// partners to exclude from getting data + public static void setSharingFilter(params string[] partners) + { +#if !UNITY_EDITOR + _setSharingFilter(partners.Length, partners); +#endif + } + + /// + /// To record an impression use the following API call. + /// Make sure to use the promoted App ID as it appears within the AppsFlyer dashboard. + /// + /// promoted App ID. + /// cross promotion campaign. + /// parameters Dictionary. + public static void recordCrossPromoteImpression(string appID, string campaign, Dictionary parameters) + { +#if !UNITY_EDITOR + _recordCrossPromoteImpression(appID, campaign, AFMiniJSON.Json.Serialize(parameters)); +#endif + } + + /// + /// Use the following API to attribute the click and launch the app store's app page. + /// + /// promoted App ID + /// cross promotion campaign + /// additional user params + public static void attributeAndOpenStore(string appID, string campaign, Dictionary parameters, MonoBehaviour gameObject) + { +#if !UNITY_EDITOR + _attributeAndOpenStore(appID, campaign, AFMiniJSON.Json.Serialize(parameters), gameObject ? gameObject.name : null); +#endif + } + + /// + /// The LinkGenerator class builds the invite URL according to various setter methods which allow passing on additional information on the click. + /// See - https://support.appsflyer.com/hc/en-us/articles/115004480866-User-invite-attribution- + /// + /// parameters Dictionary. + public static void generateUserInviteLink(Dictionary parameters, MonoBehaviour gameObject) + { +#if !UNITY_EDITOR + _generateUserInviteLink(AFMiniJSON.Json.Serialize(parameters), gameObject ? gameObject.name : null); +#endif + } + + /// + /// It is recommended to generate an in-app event after the invite is sent to record the invites from the senders' perspective. + /// This enables you to find the users that tend most to invite friends, and the media sources that get you these users. + /// + /// channel string. + /// parameters Dictionary.. + public static void recordInvite(string channel, Dictionary parameters) + { +#if !UNITY_EDITOR + _recordInvite(channel, AFMiniJSON.Json.Serialize(parameters)); +#endif + } + + + /* + * AppsFlyer ios method mapping + */ + + [DllImport("__Internal")] + private static extern void _startSDK(); + + [DllImport("__Internal")] + private static extern void _getConversionData(string objectName); + + [DllImport("__Internal")] + private static extern void _setCustomerUserID(string customerUserID); + + [DllImport("__Internal")] + private static extern void _setAdditionalData(string customData); + + [DllImport("__Internal")] + private static extern void _setAppsFlyerDevKey(string appsFlyerDevKey); + + [DllImport("__Internal")] + private static extern void _setAppleAppID(string appleAppID); + + [DllImport("__Internal")] + private static extern void _setCurrencyCode(string currencyCode); + + [DllImport("__Internal")] + private static extern void _setDisableCollectAppleAdSupport(bool disableCollectAppleAdSupport); + + [DllImport("__Internal")] + private static extern void _setIsDebug(bool isDebug); + + [DllImport("__Internal")] + private static extern void _setShouldCollectDeviceName(bool shouldCollectDeviceName); + + [DllImport("__Internal")] + private static extern void _setAppInviteOneLinkID(string appInviteOneLinkID); + + [DllImport("__Internal")] + private static extern void _anonymizeUser(bool shouldAnonymizeUser); + + [DllImport("__Internal")] + private static extern void _setDisableCollectIAd(bool disableCollectIAd); + + [DllImport("__Internal")] + private static extern void _setUseReceiptValidationSandbox(bool useReceiptValidationSandbox); + + [DllImport("__Internal")] + private static extern void _setUseUninstallSandbox(bool useUninstallSandbox); + + [DllImport("__Internal")] + private static extern void _setResolveDeepLinkURLs(int length, params string[] resolveDeepLinkURLs); + + [DllImport("__Internal")] + private static extern void _setOneLinkCustomDomains(int length, params string[] oneLinkCustomDomains); + + [DllImport("__Internal")] + private static extern void _setUserEmails(EmailCryptType cryptType, int length, params string[] userEmails); + + [DllImport("__Internal")] + private static extern void _setPhoneNumber(string phoneNumber); + + [DllImport("__Internal")] + private static extern void _afSendEvent(string eventName, string eventValues); + + [DllImport("__Internal")] + private static extern void _validateAndSendInAppPurchase(string productIdentifier, string price, string currency, string tranactionId, string additionalParameters, string objectName); + + [DllImport("__Internal")] + private static extern void _recordLocation(double longitude, double latitude); + + [DllImport("__Internal")] + private static extern string _getAppsFlyerId(); + + [DllImport("__Internal")] + private static extern void _registerUninstall(byte[] deviceToken); + + [DllImport("__Internal")] + private static extern void _handlePushNotification(string pushPayload); + + [DllImport("__Internal")] + private static extern string _getSDKVersion(); + + [DllImport("__Internal")] + private static extern void _setHost(string host, string hostPrefix); + + [DllImport("__Internal")] + private static extern void _setMinTimeBetweenSessions(int minTimeBetweenSessions); + + [DllImport("__Internal")] + private static extern void _stopSDK(bool isStopSDK); + + [DllImport("__Internal")] + private static extern bool _isSDKStopped(); + + [DllImport("__Internal")] + private static extern void _handleOpenUrl(string url, string sourceApplication, string annotation); + + [DllImport("__Internal")] + private static extern void _setSharingFilterForAllPartners(); + + [DllImport("__Internal")] + private static extern void _setSharingFilter(int length, params string[] partners); + + [DllImport("__Internal")] + private static extern void _recordCrossPromoteImpression(string appID, string campaign, string parameters); + + [DllImport("__Internal")] + private static extern void _attributeAndOpenStore(string appID, string campaign, string parameters, string gameObject); + + [DllImport("__Internal")] + private static extern void _generateUserInviteLink(string parameters, string gameObject); + + [DllImport("__Internal")] + private static extern void _recordInvite(string channel, string parameters); + + } + +#endif + + +} \ No newline at end of file diff --git a/Runtime/AppsFlyeriOS.cs.meta b/Runtime/AppsFlyeriOS.cs.meta new file mode 100644 index 0000000..c876520 --- /dev/null +++ b/Runtime/AppsFlyeriOS.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 120dceef0eff140d7b70376e9f0a1202 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/IAppsFlyerConversionData.cs b/Runtime/IAppsFlyerConversionData.cs new file mode 100644 index 0000000..454eaa6 --- /dev/null +++ b/Runtime/IAppsFlyerConversionData.cs @@ -0,0 +1,31 @@ +namespace AppsFlyerSDK +{ + public interface IAppsFlyerConversionData + { + /// + /// `conversionData` contains information about install. Organic/non-organic, etc. + /// https://support.appsflyer.com/hc/en-us/articles/360000726098-Conversion-Data-Scenarios#Introduction + /// + /// JSON string of the returned conversion data. + void onConversionDataSuccess(string conversionData); + + /// + /// Any errors that occurred during the conversion request. + /// + /// A string describing the error. + void onConversionDataFail(string error); + + /// + /// `attributionData` contains information about OneLink, deeplink. + /// https://support.appsflyer.com/hc/en-us/articles/208874366-OneLink-Deep-Linking-Guide#Intro + /// + /// JSON string of the returned deeplink data. + void onAppOpenAttribution(string attributionData); + + /// + /// Any errors that occurred during the attribution request. + /// + /// A string describing the error. + void onAppOpenAttributionFailure(string error); + } +} \ No newline at end of file diff --git a/Runtime/IAppsFlyerConversionData.cs.meta b/Runtime/IAppsFlyerConversionData.cs.meta new file mode 100644 index 0000000..3e25bce --- /dev/null +++ b/Runtime/IAppsFlyerConversionData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c2148c64eaa7b4a44a76b14de953ffcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/IAppsFlyerUserInvite.cs b/Runtime/IAppsFlyerUserInvite.cs new file mode 100644 index 0000000..aac109e --- /dev/null +++ b/Runtime/IAppsFlyerUserInvite.cs @@ -0,0 +1,26 @@ +namespace AppsFlyerSDK +{ + public interface IAppsFlyerUserInvite + { + /// + /// The success callback for generating OneLink URLs. + /// + /// A string of the newly created url. + void onInviteLinkGenerated(string link); + + /// + /// The error callback for generating OneLink URLs + /// + /// A string describing the error. + void onInviteLinkGeneratedFailure(string error); + + /// + /// (ios only) iOS allows you to utilize the StoreKit component to open + /// the App Store while remaining in the context of your app. + /// More details at https://support.appsflyer.com/hc/en-us/articles/115004481946-Cross-Promotion-Tracking#tracking-cross-promotion-impressions + /// + /// openStore callback Contains promoted `clickURL` + void onOpenStoreLinkGenerated(string link); + + } +} \ No newline at end of file diff --git a/Runtime/IAppsFlyerUserInvite.cs.meta b/Runtime/IAppsFlyerUserInvite.cs.meta new file mode 100644 index 0000000..e6b08dc --- /dev/null +++ b/Runtime/IAppsFlyerUserInvite.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3add604d2b2ac47269f4e3c24a5ef62a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/IAppsFlyerValidateReceipt.cs b/Runtime/IAppsFlyerValidateReceipt.cs new file mode 100644 index 0000000..90490e2 --- /dev/null +++ b/Runtime/IAppsFlyerValidateReceipt.cs @@ -0,0 +1,19 @@ +namespace AppsFlyerSDK +{ + public interface IAppsFlyerValidateReceipt + { + /// + /// The success callback for validateAndSendInAppPurchase API. + /// For Android : the callback will return "Validate success". + /// For iOS : the callback will return a JSON string from apples verifyReceipt API. + /// + /// + void didFinishValidateReceipt(string result); + + /// + /// The error callback for validateAndSendInAppPurchase API. + /// + /// A string describing the error. + void didFinishValidateReceiptWithError(string error); + } +} \ No newline at end of file diff --git a/Runtime/IAppsFlyerValidateReceipt.cs.meta b/Runtime/IAppsFlyerValidateReceipt.cs.meta new file mode 100644 index 0000000..e44c3bb --- /dev/null +++ b/Runtime/IAppsFlyerValidateReceipt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ccadc8fd86194a66b791b2509477fb4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Unity.AppsFlyer.asmdef b/Runtime/Unity.AppsFlyer.asmdef new file mode 100644 index 0000000..a02176e --- /dev/null +++ b/Runtime/Unity.AppsFlyer.asmdef @@ -0,0 +1,3 @@ +{ + "name": "AppsFlyer" +} diff --git a/Runtime/Unity.AppsFlyer.asmdef.meta b/Runtime/Unity.AppsFlyer.asmdef.meta new file mode 100644 index 0000000..de17426 --- /dev/null +++ b/Runtime/Unity.AppsFlyer.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c3b2ad556d41d1441bfade97a3c348cd +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests.meta b/Tests.meta new file mode 100644 index 0000000..7e94aff --- /dev/null +++ b/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a77679e48ebfd24f9fb2339caa3b7e8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 0000000..cb72949 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "com.powerplaystudio.appsflyer", + "version": "0.0.1", + "displayName": "AppsFlyer", + "description": "Package wrapper for AppsFlyer Unity SDK", + "unity": "2019.3", + "unityRelease": "11f1", + "dependencies": { + }, + "keywords": [ + "keyword1", + "keyword2", + "keyword3" + ], + "author": { + "name": "Michal Ferko", + "email": "michalferko1@gmail.com", + "url": "https://powerplay.studio" + } +} \ No newline at end of file diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..12c5c99 --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fac9e42308ce4de439a5a2223becd29d +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: