1try{let e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},t=(new e.Error).stack;t&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[t]="faa36f5d-9b3d-4dc8-956d-c79b21cb2017",e._sentryDebugIdIdentifier="sentry-dbid-faa36f5d-9b3d-4dc8-956d-c79b21cb2017")}catch(e){}(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[80],{33796:function(e,t,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/deep-dives/threads",function(){return s(42326)}])},13949:function(e,t,s){"use strict";s.d(t,{Z:function(){return r}});var a=s(54381),i=s(27397);function r(e){let{children:t,added:s,showLineNumbers:r,wrapLines:n,caption:o}=e;return(0,a.jsx)(i.y,{language:"basic",added:s,showLineNumbers:r,wrapLines:n,caption:o,children:t})}},27397:function(e,t,s){"use strict";s.d(t,{y:function(){return T}});var a=s(54381),i=s(39750),r=s(8018),n=s(15392),o=s(73749),l=s(18414),d=s(81338),c=s(33749),h=s(99883),m=s(31338),p=s(21752),u=s(17102),f=s(41411),g=s(44088),w=s(77649),x=s(93950),b=s(43379),j=s(20047);let v={added:"#0f7121"},y={groovy:h.Z,kotlin:p.Z,objectivec:u.Z,shell:g.Z,swift:w.Z,basic:d.Z,json:m.Z,cpp:c.Z,plaintext:f.Z,yaml:x.Z};function T(e){let{language:t,children:s,added:d,showLineNumbers:c,wrapLines:h,caption:m,hideCopyButton:p}=e,[u,f]=(0,o.useState)(!1),g=(0,o.useCallback)(()=>{navigator.clipboard.writeText(s),f(!0),setTimeout(()=>f(!1),3e3)},[s]);return l.Z.registerLanguage(t,y[t]),(0,a.jsxs)("div",{className:"tw-my-2",children:[(0,a.jsxs)("div",{className:"tw-relative tw-group",children:[!p&&(0,a.jsx)(i.z,{plain:!0,onClick:g,className:"tw-absolute tw-right-1 tw-top-1 tw-p-2","aria-label":u?"Copied!":"Copy code",children:u?(0,a.jsx)(r.Z,{className:"tw-h-4 tw-w-4"}):(0,a.jsx)(n.Z,{className:"tw-h-4 tw-w-4"})}),(0,a.jsx)(l.Z,{className:"rounded mb-3 p-2 tw-text-base",language:t,style:"kotlin"===t?b.Z:j.Z,wrapLines:h,showLineNumbers:c,lineProps:e=>{let t={display:"block"};return(null==d?void 0:d.includes(e))&&(t.backgroundColor=v.added),{style:t}},children:s})]}),m?(0,a.jsx)("div",{className:"text-center fs--1 pt-2 text-light",children:m}):""]})}},4740:function(e,t,s){"use strict";function a(e){return e.children}s.d(t,{Z:function(){return a}})},50794:function(e,t,s){"use strict";var a=s(54381),i=s(28093),r=s.n(i);s(73749);var n=s(44759);s(38189),t.Z=e=>{let{imageSrc:t,width:s,alt:i,caption:o}=e;return(0,a.jsxs)("div",{className:"text-center tw-mb-2",children:[(0,a.jsx)(n.Z,{children:(0,a.jsx)("div",{className:" p-2",children:(0,a.jsx)(r(),{className:"img-rounded mw-100",src:t,width:s||800,height:s?Math.round(.5625*s):450,alt:i,style:{maxWidth:"100%",height:"auto"}})})}),o?(0,a.jsx)("div",{className:"text-center fs--1 pb-2 text-light tw-break-words",children:o}):null]})}},6590:function(e,t,s){"use strict";var a=s(54381);t.Z=e=>{let{children:t}=e;return(0,a.jsx)("div",{className:"tw-pt-6 tw-pb-2",children:(0,a.jsx)("div",{className:"tw-border-t tw-border-t-[#ffffff26]",children:t})})}},19338:function(e,t,s){"use strict";s.d(t,{f:function(){return n}});var a=s(54381),i=s(91082),r=s(50794);function n(e){let{treemapJson:t,appName:s,platform:n,hideBreadcrumb:o,categories:l=[],imgSrc:d,imgAlt:c,imgCaption:h}=e;return(0,a.jsxs)("div",{children:[(0,a.jsx)("div",{className:"md:tw-hidden tw-block tw-mb-4",children:(0,a.jsx)(r.Z,{imageSrc:d,width:800,alt:c,caption:h})}),(0,a.jsx)("div",{className:"tw-hidden md:tw-block tw-mb-5 tw-mt-2",children:(0,a.jsx)(i.o,{treemap:t,modules:[],categories:l,insights:[],platform:n,name:s,roamEnabled:!1,hideBreadcrumb:o,previewToken:null,uploadId:null,contentTreemap:!0})})]})}t.Z=n},61625:function(e,t,s){"use strict";s.d(t,{Z:function(){return d},t:function(){return l}});var a=s(54381),i=s(77730),r=s(74605),n=s(19338);let o=e=>fetch(e).then(e=>e.json());function l(e){let{dataPath:t,imagePath:s,platform:l,appName:d,imgAlt:c,imgCaption:h}=e,{data:m}=(0,r.Z)(t,o);return m?(0,a.jsx)(n.f,{treemapJson:m,platform:l,hideBreadcrumb:!1,appName:d,imgSrc:s,imgAlt:c,imgCaption:h}):(0,a.jsx)(i.Z,{})}function d(e){let{dataPath:t,imagePath:s}=e;return(0,a.jsx)(l,{dataPath:t,imagePath:s,platform:"ios",appName:"Acorns",imgAlt:"X-Ray of Acorns iOS",imgCaption:"X-Ray of Acorns iOS (interactive on larger screens)"})}},7967:function(e,t,s){"use strict";var a=s(54381),i=s(30537),r=s(12315),n=s.n(r);s(38189);var o=s(69548),l=s(76830),d=s(38499),c=s(11508),h=s(25335),m=s(88012),p=s(6590),u=s(66149),f=s(67411);t.Z=e=>{var t;let{appName:s,appIconSrc:r,seoMetadata:g,impressionLoggingId:w,recommendedReadingOptions:x,children:b}=e;return g.imageURL=null!==(t=g.imageURL)&&void 0!==t?t:"https://emergeassets.s3.us-west-1.amazonaws.com/glossary-seo.png",(0,a.jsxs)("div",{className:"space-bg min-vh-100",children:[(0,a.jsx)(h.Z,{loggingId:"deepdive-".concat(w)}
1),(0,a.jsx)(i.PB,{...(0,c.b)({title:g.title,description:g.description,imageURL:g.imageURL})}),(0,a.jsx)(d.Z,{}),(0,a.jsx)(u.Z,{children:(0,a.jsxs)("div",{className:"mx-4 mb-4 w-sm-75 mx-sm-auto text-white fs-1 tw-pt-24",style:{maxWidth:"800px",lineHeight:"1.6"},children:[(0,a.jsxs)("div",{className:"pb-3 d-flex tw-items-center mb-3",style:{borderBottom:"1px solid #fffff260"},children:[(0,a.jsx)("div",{className:"tw-mr-3 tw-flex",children:(0,a.jsx)(n(),{src:r,className:"tw-rounded-md tw-border-solid tw-border-slate-400",quality:100,width:40,height:40,alt:"App icon for ".concat(s)})}),(0,a.jsx)("h1",{className:"text-white w-100 tw-mb-0",children:s})]}),(0,a.jsx)("div",{id:"content-body",className:"tw-text-white",children:b}),(0,a.jsx)("div",{className:"py-3",children:(0,a.jsx)(o.AI,{screenName:"emergetools",options:{showCount:!1}})}),(0,a.jsxs)(p.Z,{children:[(0,a.jsx)(m.Z,{}),(0,a.jsx)(f.Z,{recommended:x})]})]})}),(0,a.jsx)(l.Z,{})]})}},33863:function(e,t,s){"use strict";s.d(t,{F_:function(){return n},Vb:function(){return o},qz:function(){return r},vY:function(){return l}});var a=s(33545),i=s.n(a);async function r(e){let t={...i().query};for(let s of e)delete t[s];await i().replace({pathname:i().pathname,query:t},void 0,{shallow:!0})}async function n(e){let t={...i().query};for(let{key:s,value:a}of e)a?t[s]=a.toString():delete t[s];await i().replace({pathname:i().pathname,query:t},void 0,{shallow:!0})}async function o(e,t){let s={...e.query};for(let{key:e,value:a}of t)a?a instanceof Date?s[e]=a.toISOString():s[e]=a.toString():delete s[e];await e.replace({pathname:e.pathname,query:s},void 0,{shallow:!0})}function l(e){let t={id:e,badges:[],title:"",identifier:"",subtitle:void 0,imageUrl:"",width:0,height:0,additionalInfo:void 0,s3Prefix:null};return{title:"loading",badges:[],subtitle:void 0,diffImageInfo:{imageUrl:""},width:0,height:0,baseSnapshot:t,headSnapshot:t,ignored:null}}},42326:function(e,t,s){"use strict";s.r(t);var a=s(54381),i=s(4496),r=s(77603);s(38189);var n=s(13949),o=s(4740),l=s(50794),d=s(69619),c=s(61625),h=s(7967),m=s(38340);let p=e=>{let{isAndroid:t,analysisLink:s,version:i,size:r}=e;return(0,a.jsxs)("div",{children:[(0,a.jsx)(d.Z,{href:s,children:"Analysis Link"}),(0,a.jsxs)("div",{className:"tw-flex",children:[(0,a.jsx)("span",{className:"tw-font-semibold",children:"Version:\xa0"}),(0,a.jsx)("span",{children:i})]}),(0,a.jsxs)("div",{className:"tw-flex",children:[(0,a.jsxs)("span",{className:"tw-font-semibold",children:[t?"Download":"Install"," Size:\xa0"]}),(0,a.jsxs)("span",{children:[r," MB"]})]})]})},u=()=>(0,a.jsx)(h.Z,{appName:"Threads",appIconSrc:"/images/deepDives/threads/threads.png",impressionLoggingId:"threads",seoMetadata:{title:"Emerge Tools | Threads Deep Dive",description:"Emerge Tools analysis of the Threads app",imageURL:"https://emergeassets.s3.us-west-1.amazonaws.com/threads.png"},recommendedReadingOptions:[m.d.BLOG_ettrace],children:(0,a.jsxs)("div",{children:[(0,a.jsx)("i",{children:"July 7, 2023"}),(0,a.jsx)("p",{children:"Threads is a new app from the Instagram team for âfor sharing text updates and joining public conversations.â Maybe this was in the plans for awhile, maybe the Meta / Instagram team thought that people might be looking for a new app for sharing updates with text \uD83E\uDD37."}),(0,a.jsxs)("p",{children:["Meta has dedicated significant in-house resources to optimizing mobile performance. You can look through our analysis for ",(0,a.jsx)(d.Z,{href:"/explore",children:"any app"})," and where many apps are loaded with Emerge Insights, Meta mobile apps are highly optimized. Meta uses some patterns that aren't a typical best practice, but Meta has the infrastructure and engineering power to pull it off well."]}),(0,a.jsxs)("h2",{className:"tw-text-white",children:[(0,a.jsx)(r.G,{icon:i.usd,className:"mr-2"}),"Threads Android App"]}),(0,a.jsx)(p,{isAndroid:!0,analysisLink:"https://www.emergetools.com/app/example/android/com.instagram.barcelona",version:"289.0.0.77.109",size:"72.3"}),(0,a.jsx)(c.t,{dataPath:"/images/deepDives/threads/threads-android-treemap.json",platform:"android",appName:"Threads",imagePath:"/images/deepDives/threads/androidTreemap.png",imgAlt:"Emerge X-Ray of the Threads Android app"}),(0,a.jsxs)("ul",{children:[(0,a.jsxs)("li",{children:["Like other Meta apps, Threads is being shipped as a universal APK. AABs are considered a best practice, but Meta aggressively optimizes its universal APKs â obfuscating resources, custom packaging shared libraries, and using ",(0,a.jsx)(d.Z,{href:"https://github.com/facebook/redex",children:"Redex"}),"."]}),(0,a.jsxs)("li",{children:["It was surprising to see Threads is shipping debug code. Threads has debug packages like"," ",(0,a.jsx)("code",{children:"com.instagram.debug.devoptions.sandboxselector"})," and"," ",(0,a.jsx)("code",{children:"com.instagram..debug.quickexperiment"}),"."]}),(0,a.jsxs)("li",{children:["Theyâre using React Native for some portion of the app - ",(0,a.jsx)("code",{children:"InstagramBundle.js.hbc.spk.xz"})," is likely a compressed version of ",(0,a.jsx)(d.Z,{href:"https://hermesengine.dev/",children:"Hermes"})," bytecode (",(0,a.jsx)("code",{children:"js.hbc"}),")"]}),(0,a.jsxs)("li",{children:["Thereâs a large ",(0,a.jsx)("code",{children:".spo"})," file that looks like a compiled version of different native libraries. Thereâs a metadata file packaged with it:",(0,a.jsx)("div",{className:"tw-my-2",children:(0,a.jsx)(n.Z,{children:"arm64-v8a/librtc.so 11336240 bda527a307edd868700fccfab15481f403d3f39363289d5d6a717579f284bed7\narm64-v8a/libgojni.so 11330024
1616915938eb1face6aa3392aedab8bddce280f2b84423377ac65896a6b3faad7\narm64-v8a/libarfxgraphicsmerged.so 9710600 afb00aa881a63b20371e447dbbad61fefcf4df2c23c922a9e44e2171d7a649ad\n..."})}),"Our guess is that the .spo file is a merged version of all native libraries, second entry is the offset / size, third entry is the checksum"]}),(0,a.jsxs)("li",{children:["From @richz's (Threads engineer)"," ",(0,a.jsx)(d.Z,{href:"https://www.threads.net/t/CuW_fXZOgPc/",children:"post"}),", Threads is largely using Jetpack Compose for its UI. The compose portion of the dex is relatively small (~130 KB) compared to the overall dex size. This could mean that they are efficient in their usage of Compose and/or they shared code from Instagram, making the usage appear less than what it is."]})]}),(0,a.jsx)("h3",{className:"tw-text-white",children:"Similarities with the Instagram App"}),(0,a.jsxs)("p",{children:["Threads appears to share a lot with the"," ",(0,a.jsx)(d.Z,{href:"https://www.emergetools.com/app/example/android/com.instagram.android",children:"Instagram app"})," ","(v289.0.0.25.49). The aforementioned ",(0,a.jsx)("code",{children:"InstagramBundle.js.hbc.spk.xz"})," is similar for Threads & IG. The",(0,a.jsx)("code",{children:"/assets/dsp"})," is also the same between both apps. It makes sense that these apps would share code seeing as Threads is heavily integrated with Instagram."]}),(0,a.jsxs)("h2",{className:"tw-text-white",children:[(0,a.jsx)(r.G,{icon:i.Av$,className:"mr-2"}),"Threads iOS App"]}),(0,a.jsx)(p,{isAndroid:!1,analysisLink:"https://emergetools.com/app/example/ios/com.burbn.barcelona",version:"289.0",size:"244.2"}),(0,a.jsx)(c.t,{dataPath:"/images/deepDives/threads/threads-ios-treemap.json",imagePath:"/images/deepDives/threads/iosTreemap.png",platform:"ios",appName:"Threads",imgAlt:"Emerge X-Ray of the Threads iOS app"}),(0,a.jsx)("p",{children:"Two things stand out for Threads on iOS:"}),(0,a.jsxs)("ol",{children:[(0,a.jsxs)("li",{children:["Threads has 0 dynamic libraries, whereas the"," ",(0,a.jsx)(d.Z,{href:"https://www.emergetools.com/app/example/ios/com.facebook.Facebook",children:"Facebook app"})," ","which"," ",(0,a.jsx)(d.Z,{href:"https://engineering.fb.com/2023/02/06/ios/facebook-ios-app-architecture/",children:"heavily utilizes"})," ","dynamic frameworks."]}),(0,a.jsxs)("li",{children:["Threads has one of the largest plugins weâve ever seen. ",(0,a.jsx)("code",{children:"BarcelonaShareExtension"})," is 81 MB. For context, the largest"," ",(0,a.jsx)(d.Z,{href:"https://emergetools.com/app/example/ios/com.burbn.instagram",children:"Instagram"})," ","plugin - ",(0,a.jsx)("code",{children:"InstagramNotificationExtension"})," is 23.5 MB. The",(0,a.jsx)("code",{children:"InstagramShareExtension"})," is 5.6 MB"]})]}),(0,a.jsxs)("p",{children:["Interestingly, Instagramâs ",(0,a.jsx)("code",{children:"FBSharedFramework"})," shares a lot of the same elements as Threadâs BarcelonaShareExtension."]}),(0,a.jsx)("p",{children:"Some notable shared elements"}),(0,a.jsxs)("ul",{children:[(0,a.jsx)("li",{children:(0,a.jsx)("code",{children:"FilterAsset.bundle"})}),(0,a.jsxs)("li",{children:[(0,a.jsx)("code",{children:"ig_signals_cupid_better_recall_v1.mlmodelc"})," & ",(0,a.jsx)("code",{children:"ig_signals_cupid_v2.mlmodelc"})]}),(0,a.jsx)("li",{children:"The asset catalog is almost the exact same"})]}),(0,a.jsx)("p",{children:"As with the Android app, it looks like they were able to share significant amounts of code between Threads & Instagram to help speed up development. Threads team wanted to move fast and took whatever code it could from Instagram and shoved it where it needed to go."}),(0,a.jsx)("h3",{className:"tw-text-white",children:"Looking at Threads Startup Time"}),(0,a.jsxs)("p",{children:["While much of our X-Ray is obfuscated, we were able to use"," ",(0,a.jsx)(d.Z,{href:"https://github.com/emergeTools/ettrace",children:"ETTrace"})," to look at Threads Startup time"]}),(0,a.jsx)(l.Z,{width:800,imageSrc:"/images/deepDives/threads/ettrace.gif",alt:"GIF of generating a flame chart of Threads startup with ETTrace",caption:"Generating a flame chart of Threads startup with ETTrace"}),(0,a.jsxs)("p",{children:["If you want to see Threadâs startup time for yourself, you can download this"," ",(0,a.jsx)("a",{href:"/images/deepDives/threads/threads_startup.json",download:!0,children:"JSON file"})," ","and upload it to ",(0,a.jsx)(d.Z,{href:"https://www.emergetools.com/flamegraph",children:"ETTrace"}),"."]}),(0,a.jsx)("p",{children:"Weâre working with obfuscated builds so thereâs only so much you can get from a stack trace. We do see that thereâs a good amount of pre-main time (~50 MS from the trace collected)."}),(0,a.jsxs)("p",{children:["Thereâs also a ",(0,a.jsx)("code",{children:"WKWebView"})," initialized in app launch, which is pretty slow. This suggests that their sign-in experience isnât native and they are showing a webview, or they are using it in the background for tracking purposes."]}),(0,a.jsx)(l.Z,{imageSrc:"/images/deepDives/threads/webviewSpan.png",width:800,alt:"Highlight of WKWebView in Threads' startup",caption:"Highlight of `WKWebView` in Threads' startup"}),(0,a.jsx)("h2",{className:"tw-text-white",children:"TL;DR"}),(0,a.jsx)("p",{children:"There's only so much we can gather looking at public Meta builds, but it looks like Threads is heavily borrowing from Instagram on both platforms. Will be interesting to see if that changes."})]})});u.Layout=o.Z,t.default=u},11508:function(e,t,s){"use strict";s.d(t,{b:function(){return r}});var a=s(33545),i=s(32559);let r=e=>{let{title:t,description:s,imageURL:r}=e,n=(0,a.useRouter)(),o=i.env.VERCEL_URL||"www.emergetools.com";return"https://www.".concat(o).concat(n.pathname),{title:t,description:s,openGraph:{type:"website",locale:"en_US",url:window.location.href,title:t,description:s,images:[{url:r,width:1022,height:500}]}}}},2771:function(e,t,s){"use strict";function a(e){let t=!(arguments.length>1)||void 0===arguments[1]||arguments[1],s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;if(0!==e&&!e)return null;let a=t?1e3:1024;if(Math.abs(e)<a)return"".concat(e," B");let i=t?["kB","MB","GB","TB","PB","EB","ZB","YB"]:["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],r=-1,n=10**s;do e/=a,++r;
1while(Math.round(Math.abs(e)*n)/n>=a&&r<i.length-1);return"".concat(e.toFixed(s)," ").concat(i[r])}s.d(t,{g:function(){return a}})},76560:function(e,t,s){"use strict";function a(){return(a=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var s=arguments[t];for(var a in s)Object.prototype.hasOwnProperty.call(s,a)&&(e[a]=s[a])}return e}).apply(this,arguments)}s.d(t,{Z:function(){return a}})},78913:function(e,t,s){"use strict";var a=s(73749);let i=a.forwardRef(function(e,t){let{title:s,titleId:i,...r}=e;return a.createElement("svg",Object.assign({xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor","aria-hidden":"true","data-slot":"icon",ref:t,"aria-labelledby":i},r),s?a.createElement("title",{id:i},s):null,a.createElement("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"m4.5 12.75 6 6 9-13.5"}))});t.Z=i},77730:function(e,t,s){"use strict";s.d(t,{Z:function(){return r}});var a=s(73749);let i=a.createContext({});function r({count:e=1,wrapper:t,className:s,containerClassName:r,containerTestId:n,circle:o=!1,style:l,...d}){var c,h,m;let p=a.useContext(i),u={...d};for(let[e,t]of Object.entries(d))void 0===t&&delete u[e];let f={...p,...u,circle:o},g={...l,...function({baseColor:e,highlightColor:t,width:s,height:a,borderRadius:i,circle:r,direction:n,duration:o,enableAnimation:l=!0,customHighlightBackgroun
1d:d}){let c={};return"rtl"===n&&(c["--animation-direction"]="reverse"),"number"==typeof o&&(c["--animation-duration"]=`${o}s`),l||(c["--pseudo-element-display"]="none"),("string"==typeof s||"number"==typeof s)&&(c.width=s),("string"==typeof a||"number"==typeof a)&&(c.height=a),("string"==typeof i||"number"==typeof i)&&(c.borderRadius=i),r&&(c.borderRadius="50%"),void 0!==e&&(c["--base-color"]=e),void 0!==t&&(c["--highlight-color"]=t),"string"==typeof d&&(c["--custom-highlight-background"]=d),c}(f)},w="react-loading-skeleton";s&&(w+=` ${s}`);let x=null!==(c=f.inline)&&void 0!==c&&c,b=[],j=Math.ceil(e);for(let t=0;t<j;t++){let s=g;if(j>e&&t===j-1){let t=null!==(h=s.width)&&void 0!==h?h:"100%",a=e%1,i="number"==typeof t?t*a:`calc(${t} * ${a})`;s={...s,width:i}}let i=a.createElement("span",{className:w,style:s,key:t},"â");x?b.push(i):b.push(a.createElement(a.Fragment,{key:t},i,a.createElement("br",null)))}return a.createElement("span",{className:r,"data-testid":n,"aria-live":"polite","aria-busy":null===(m=f.enableAnimation)||void 0===m||m},t?b.map((e,s)=>a.createElement(t,{key:s},e)):b)}}},function(e){e.O(0,[2806,7196,7131,8246,4564,3302,6197,5194,4700,9140,1633,980,4664,3434,3897,4335,1278,7411,3484,1082,2888,9774,179],function(){return e(e.s=33796)}),_N_E=e.O()}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.