Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do A/B testing platforms replace Objective-C assets on the fly?

Leanplum, Apptimize and other A/B testing platforms for iOS have the ability to download assets (nib files ,images, etc...) from the web and replace them at runtime.

The naive approach will be to download the new assets and replace them in the resource bundle directory, but it is impossible to write files to the resource directory because of permissions.

The question is, what techniques does these A/B testing platforms use to replace assets at runtime?

EDIT:

After reading the symbols on leanplum static library file (using nm) it seems that they are Swizzling cocoa file system API's.

for example: (an example line from nm -m leanplum.a)

 -[NSBundle(LeanplumExtension) leanplum_URLForResource:withExtension:]

By using otool I can print the implementation:

-[NSBundle(LeanplumExtension) leanplum_URLForResource:withExtension:]:
0000000000000069        pushq   %rbp
000000000000006a        movq    %rsp, %rbp
000000000000006d        pushq   %r15
000000000000006f        pushq   %r14
0000000000000071        pushq   %r13
0000000000000073        pushq   %r12
0000000000000075        pushq   %rbx
0000000000000076        subq    $0x18, %rsp
000000000000007a        movq    %rcx, %rbx
000000000000007d        movq    %rdi, 0xffffffffffffffc8(%rbp)
0000000000000081        movq    %rdx, %rdi
0000000000000084        callq   _objc_retain
0000000000000089        movq    %rax, %r14
000000000000008c        movq    %rbx, %rdi
000000000000008f        callq   _objc_retain
0000000000000094        movq    %rax, 0xffffffffffffffd0(%rbp)
0000000000000098        movq    _originalMainBundle(%rip), %rcx
000000000000009f        movq    "+[NSBundle(LeanplumExtension) leanplum_mainBundle]"(%rcx), %rdi
00000000000000a2        movq    0x4487(%rip), %rsi
00000000000000a9        movq    _objc_msgSend(%rip), %r12
00000000000000b0        movq    %r14, %rdx
00000000000000b3        movq    %rax, %rcx
00000000000000b6        callq   *%r12
00000000000000b9        movq    %rax, %rdi
00000000000000bc        callq   _objc_retainAutoreleasedReturnValue
00000000000000c1        movq    %rax, %r13
00000000000000c4        movq    _skippedFiles(%rip), %rax
00000000000000cb        movq    "+[NSBundle(LeanplumExtension) leanplum_mainBundle]"(%rax), %rbx
00000000000000ce        movq    0x4463(%rip), %rsi
00000000000000d5        movq    %r13, %rdi
00000000000000d8        callq   *%r12
00000000000000db        movq    %rax, %rdi
00000000000000de        callq   _objc_retainAutoreleasedReturnValue
00000000000000e3        movq    %rax, %r15
00000000000000e6        movq    0x4453(%rip), %rsi
00000000000000ed        movq    %rbx, %rdi
00000000000000f0        movq    %r15, %rdx
00000000000000f3        callq   *%r12
00000000000000f6        movb    %al, %bl
00000000000000f8        movq    %r15, %rdi
00000000000000fb        callq   _objc_release
0000000000000100        testb   %bl, %bl
0000000000000102        je      0x115
0000000000000104        movq    %r13, %rdi
0000000000000107        callq   _objc_retain
000000000000010c        movq    %rax, %r15
000000000000010f        movq    0xffffffffffffffd0(%rbp), %rbx
0000000000000113        jmp     0x13b
0000000000000115        movq    0x4414(%rip), %rsi
000000000000011c        movq    0xffffffffffffffc8(%rbp), %rdi
0000000000000120        movq    %r14, %rdx
0000000000000123        movq    0xffffffffffffffd0(%rbp), %rbx
0000000000000127        movq    %rbx, %rcx
000000000000012a        callq   *_objc_msgSend(%rip)
0000000000000130        movq    %rax, %rdi
0000000000000133        callq   _objc_retainAutoreleasedReturnValue
0000000000000138        movq    %rax, %r15
000000000000013b        movq    %r13, %rdi
000000000000013e        callq   _objc_release
0000000000000143        movq    %rbx, %rdi
0000000000000146        callq   _objc_release
000000000000014b        movq    %r14, %rdi
000000000000014e        callq   _objc_release
0000000000000153        movq    %r15, %rdi
0000000000000156        addq    $0x18, %rsp
000000000000015a        popq    %rbx
000000000000015b        popq    %r12
000000000000015d        popq    %r13
000000000000015f        popq    %r14
0000000000000161        popq    %r15
0000000000000163        popq    %rbp
0000000000000164        jmpq    _objc_autoreleaseReturnValue
  1. Can someone verify my findings?
  2. I wonder how they get this entire list of API covered?
  3. What happens if I open an image with fopen or other C lib?
  4. How can I decipher the output of otool?
like image 977
ekeren Avatar asked Feb 18 '14 10:02

ekeren


People also ask

How does AB test Facebook ads work?

A/B testing lets you compare two versions of an ad strategy by changing variables such as ad images, ad text, audience or placement. We show each version to a segment of your audience and ensure nobody sees both, then determine which version performs best.

What is the objective of a B testing?

A/B testing allows individuals, teams and companies to make careful changes to their user experiences while collecting data on the results. This allows them to construct hypotheses and to learn why certain elements of their experiences impact user behavior.

What is AB testing for landing pages?

A/B testing refers to the comparison of two versions of the same piece of content, with one item changed on the variation. For instance, if you're A/B testing landing pages, you might create a variation of the existing one and tweak the headline.


1 Answers

The question is, what techniques does these A/B testing platforms use to replace assets at runtime?

An educated guess is that they use method swizzling to swap the implementations of standard methods (e.g. [NSBundle URLForResource:withExtension:]) with those of their own versions of those methods (e.g. [NSBundle(LeanplumExtension) leanplum_URLForResource:withExtension:]). This means that your code uses the same method that you would otherwise, but you get different behavior -- in this case, the URL that's returned depends on which version of the resource the A/B testing framework decides to present to the user.

I wonder how they get this entire list of API covered?

By working carefully. The number of methods used to load resources isn't unmanageable.

What happens if I open an image with fopen or other C lib?

I expect that the framework wouldn't be able to swap resources in such a case. There are lots of ways to load data, and the framework can't possibly anticipate all of them. But if you're using an A/B framework, you presumably want the resources to be replaced as appropriate for your testing, so it doesn't make a lot of sense to try to defeat the framework.

How can I decipher the output of tool?

For the case you've shown, learn to read assembly language. (otool has a lot of options, though, and they don't all produce assembly.)

like image 145
Caleb Avatar answered Sep 19 '22 21:09

Caleb