iOS Question Trying to wrap a third party framework

CaptKronos

Active Member
Licensed User
I have just started experimenting with B4i and the first function I have tried to implement is the ability for the user to select multiple photos from various sources. I couldn't find anything that met my requirements within the B4X forums so went Googling. I came across QBImagePicker https://github.com/questbeat/QBImagePicker. I have generated QBImagePicker.framework and it works well with a small test harness written in Objective C with Xcode. However, I am having problems with getting it working with B4i. In fact I have failed at the very first step.

Using a wrapper no more complicated than:

B4X:
test.h

#import <Foundation/Foundation.h>
//~shortname:test
//~version:1.00
//~dependsOn:QBImagePicker.framework.3

@interface test : NSObject
- (void) load;
@end
B4X:
test.m

#import "test.h"

@implementation test
- (void) load
{
    NSLog(@"load");
};
@end
i.e. The wrapper doesn't yet expose any functionality of QBImagePicker, but just adds the dependsOn.

Running a B4i app that includes the test library, the app compiles without error, starts executing the app on the simulator, the simulator loads up a white screen which then closes immediately. B4i meanwhile is "Trying to connect to the simulator" which eventually times-out.

Removing the DependsOn line and everything works as expected, i.e. the app starts running on the simulator and 'load' is written to the log.

It is as if when the simulator tries to load QBImagePicker.framework, it hates what it sees and gives up immediately without any error message. I don't see any error message in the B4i log or the simulator's log.

Using lipo I have confirmed that QBImagePicker.framework and libtest.a use the x86_64 architecture.

Can anyone provide some points? Thanks.
 
Last edited:

JanPRO

Well-Known Member
Licensed User
Hi,
please do the following:
Compile your Project in B4i for the Simulator and open the generated project in Xcode. Now run the project from Xcode on the simulator, you will receive more information about the crash now. Most probably it's a linker error, if you want you can also send me the framework and I will check it further.

Jan
 

CaptKronos

Active Member
Licensed User
Hi Jan,

That's a useful debugging tip. It looks like you are correct about linking problems:

B4X:
ld: warning: ignoring file ../../Libs/libCore.a, missing required architecture i386 in file ../../Libs/libCore.a (3 slices)
ld: warning: ignoring file ../../Libs/libiDebug2.a, missing required architecture i386 in file ../../Libs/libiDebug2.a (3 slices)
ld: warning: ignoring file ../../Libs/libtest.a, file was built for archive which is not the architecture being linked (i386): ../../Libs/libtest.a
ld: warning: ignoring file ../../Libs/QBImagePicker.framework/QBImagePicker, file was built for x86_64 which is not the architecture being linked (i386): ../../Libs/QBImagePicker.framework/QBImagePicker
Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_B4I", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IAppDelegate", referenced from:
      objc-class-ref in main.o
  "_OBJC_CLASS_$_B4IApplicationWrapper", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4ICommon", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IDebug", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4INavigationControllerWrapper", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IPage", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IRDebugUtils", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IShellBI", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IStaticModule", referenced from:
      _OBJC_CLASS_$_b4i_main in b4i_main.o
  "_OBJC_CLASS_$_test", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_IVAR_$_B4IStaticModule.___c", referenced from:
      -[b4i_main _application_start:] in b4i_main.o
  "_OBJC_METACLASS_$_B4IStaticModule", referenced from:
      _OBJC_METACLASS_$_b4i_main in b4i_main.o
ld: symbol(s) not found for architecture i386
It would appear that the compilation is targeting i386 instead of x86_64. Are you able to point me to the setting I should change?

Thanks.
 

JanPRO

Well-Known Member
Licensed User
Hi,
Are you able to point me to the setting I should change?
Yes, sure. The i386 architecture (32-bit simulator) was a required for the simulator formerly. However normally, only the x86_64 architecture is needed for the simulator today. So in order to solve your problem try to include the i386 architecture to your library:

Go to the Build settings of your Library project and set the iOS deployment target to iOS 8. Moreover set Build Active Archtiecture Only to No. Now compile your library again, it should now contain both architectures (you can check it again with the lipo tool).


Jan
 
Last edited:

CaptKronos

Active Member
Licensed User
Still not there. Following your instructions the lib and framework now includes i386.

B4X:
Architectures in the fat file: Libs/QBImagePicker.framework/QBImagePicker are: i386 x86_64 
Architectures in the fat file: Libs/libtest.a are: i386 x86_64
But running my B4i compiled app in Xcode gives:

B4X:
ld: warning: ignoring file ../../Libs/libCore.a, missing required architecture i386 in file ../../Libs/libCore.a (3 slices)
ld: warning: ignoring file ../../Libs/libiDebug2.a, missing required architecture i386 in file ../../Libs/libiDebug2.a (3 slices)
Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_B4I", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IAppDelegate", referenced from:
      objc-class-ref in main.o
  "_OBJC_CLASS_$_B4IApplicationWrapper", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4ICommon", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IDebug", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4INavigationControllerWrapper", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IPage", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IRDebugUtils", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IShellBI", referenced from:
      objc-class-ref in b4i_main.o
  "_OBJC_CLASS_$_B4IStaticModule", referenced from:
      _OBJC_CLASS_$_b4i_main in b4i_main.o
  "_OBJC_IVAR_$_B4IStaticModule.___c", referenced from:
      -[b4i_main _application_start:] in b4i_main.o
  "_OBJC_METACLASS_$_B4IStaticModule", referenced from:
      _OBJC_METACLASS_$_b4i_main in b4i_main.o
ld: symbol(s) not found for architecture i386
and checking libCore.a, there's no i386:
B4X:
Architectures in the fat file: Libs/libCore.a are: armv7 x86_64 arm64
 

CaptKronos

Active Member
Licensed User
Also, when loading the B4i app into Xcode, there is a warning 'Update to recommended settings' which I'm ignoring, and three further warnings:

Mapping architecture armv7 to i386. Ensure that this target's Architecture and Valid Architectures build settings are configured correctly for the iOS simulator platform. (in target 'B4iProject')
Mapping architecture armv7s to i386. Ensure that this target's Architecture and Valid Architectures build settings are configured correctly for the iOS simulator platform.(in target 'B4iProject')
Mapping architecture arm64 to i386. Ensure that this target's Architecture and Valid Architectures build settings are configured correctly for the iOS simulator platform.(in target 'B4iProject')

Not sure what to do about those, if anything.
 

CaptKronos

Active Member
Licensed User
I have tried again and this time I clicked on 'Update to recommended settings' which has resolved the errors I reported in post #5. The warnings in post #6 are still present but the app now starts which results in a new error

dyld: Library not loaded: @rpath/QBImagePicker.framework/QBImagePicker
Referenced from: /Users/bob/Library/Developer/CoreSimulator/Devices/F9BE6FCE-F70F-487F-9989-C0C8D35B6D04/data/Containers/Bundle/Application/77470D8A-2D14-4CA1-9281-B2C1E47F1ED6/B4iProject.app/B4iProject
Reason: image not found


I guess I haven't placed QBImagePicker.framework in the correct location. I just copied it to the Libs folder which satisfied the B4i compilation stage.
 

JanPRO

Well-Known Member
Licensed User
I guess I haven't placed QBImagePicker.framework in the correct location.
Mhhh, the Libs folder is actually the right place. I have another long-shot guess: I know the framework was written in Objective-C, but try the following dependsOn statement:
//~dependsOn:QBImagePicker.framework.swift.3

Jan
 

CaptKronos

Active Member
Licensed User
Testing by running the B4i app (with the swift dependson) from Xcode I again get the image not found error. However, if I change the Xcode setting: Build Phases - Embed Frameworks - from 'Frameworks' to 'Product Directory', it works. Or at least I get to the point where the simulator displays the message 'Waiting for IDE to connect...'

and there is a continuous stream of the following messages written to the Target Output log:
B4X:
.
.
.
2019-01-27 10:13:12.590681+0000 B4iProject[15461:419943] NSURLConnection finished with error - code -1022
2019-01-27 10:13:12.792902+0000 B4iProject[15461:419740] Cannot start load of Task <CD39D9C0-A605-41AD-AC4A-42FF6016308A>.<0> since it does not conform to ATS policy
2019-01-27 10:13:12.793247+0000 B4iProject[15461:419943] NSURLConnection finished with error - code -1022
2019-01-27 10:13:12.996896+0000 B4iProject[15461:419740] Cannot start load of Task <65113525-AE28-49B7-A43F-69A185363802>.<0> since it does not conform to ATS policy
.
.
.
Does that make sense?

Anyway, running from the B4i IDE seems to be working. Now to try the difficult bit of actually exposing the framework's functionality.
 

CaptKronos

Active Member
Licensed User
With regards the log messages in the above post (#10), that was (obviously) caused by deploying the Debug build. Using the Release build, it runs as expected.
Thanks again.
 
Top