iOS Tutorial [Objective C] Writing libraries for B4i

B4i libraries are written in Objective C. You need to use a Mac with Xcode and you need to know Objective C.
From my experience it is more difficult to write B4i libraries compared to B4A / B4J libraries.

Libraries are made of three files: library.a, library.h and library.xml.

The xml file is created automatically from the h file using the tool attached to this thread.
This is a command line tool written with B4J. You need to pass two arguments: path to the h file and path to the output file.
For example:
B4X:
java -jar B4Ih2xml.jar test.h test.xml
Note that this tool parses the file line by line. It will not handle properly signatures that span multiple lines.

The a and h files should be eventually copied to the Libs folder on the Mac and the xml file should be copied to the IDE libraries folder.

Libraries should include two binaries: arm64 and armv7.

Supported types

The following types can be exposed to B4i: BOOL, unsigned char, unichar, short, int, long long, float, double and any objc object. Other types cannot be directly exposed.

Header file

The xml is derived from a single h file. This means that all the interfaces that should be exposed need to be defined in this h file.
You need to add all kinds of attributes to the h file (similar to B4A annotations).
This is done by writing a comment that starts with:
//~

For example:
B4X:
//~shortname:LocationManager
//~event:LocationChanged (Location1 As Location)
//~event:AuthorizationStatusChanged (Status As int)
//~event:LocationError
//~event:HeadingChanged (MagneticHeading As Double, TrueHeading As Double)
//~event:AllowCalibration As Boolean
//~version:1.00
//~dependsOn:CoreLocation.framework
@interface B4ILocationManager : NSObject<CLLocationManagerDelegate>

The attributes are case-insensitive and the values are trimmed from extra spaces.

Attributes
  • ShortName - The B4i type name.
  • Event - The type events. Can be used multiple times.
  • Version - library version
  • Author - library author
  • RaisesSynchronousEvents - Tells the compiler that calling this method may cause an event to be raised (before the code returns).
    //~RaisesSynchronousEvents:true
  • ObjectWrapper - If the type is a thin wrapper and it inherits from B4IObjectWrapper then this attribute should be set with the native type name.
    //~ObjectWrapper:CLLocation*
  • DependsOn - Tells the compiler that this library depends on other frameworks or a files.
    //~dependsOn:CoreLocation.framework
    If the framework is an external framework then you need to add .3:
    //~dependson:GoogleMaps.framework.3
    DependsOn with a file (the extension is omitted):
    //~dependson:GoogleAdMobAds
Methods

The exposed methods can have any number of parameters. However the parameter names should be empty:
B4X:
- (B4IMarker *)AddMarker: (double)Lat :(double)Lon :(NSString *)Title;

B4IObjectWrapper

If your object is a thin wrapper over a different object then you can inherit from B4IObjectWrapper. Such objects should not have any instance variables (including not properties that are implicitly back by a variable).
You need to create a class method named getClass that returns the native object class:
B4X:
+(Class)getClass {
  return [CLLocation class];
}

Don't use this type if you are not sure.


Raising events / B4I object

The B4I object is similar to B4A/B4J BA object. You use this object to raise events.
B4IObjectWrapper includes several class methods that help with raising events. You can use it even if your class doesn't subclass B4IObjectWrapper.

The first method is:
B4X:
[B4IObjectWrapper setBIAndEventName:self :bi :EventName];
This method takes the B4I object and the EventName parameter and stores them in the object associated map. The bi object is stored with a weak reference.
It is important to remember that the bi and EventName are tied to the object passed to this method. In this case it is 'self'.

Raising event:
B4X:
[B4IObjectWrapper raiseEvent:self :@"_authorizationstatuschanged:" :@[@((int)status)]];
Don't forget to include the colons in the method name!

Two similar methods: raiseUIEvent and raiseEventFromDifferentThread. These methods send a message to the message queue which will cause the event to be raised when the message is processed.

Tips

- Add a reference to iCore.h in your library project.

Two libraries projects are attached. The iLocation library and iAdMob library.

Latest version of iAdMob is available here: https://github.com/AnywhereSoftware/B4i_iAdMob
 

Attachments

  • Libraries.zip
    101.8 KB · Views: 756
  • B4Ih2xml.jar
    98.2 KB · Views: 453
Last edited:

JanPRO

Well-Known Member
Licensed User

Ju Yang

Active Member
Licensed User
hi, I follow the tutorial and make a lib, when I use it in B4I, I got a build error:

Ld Payload/result.app/result normal armv7
cd /Users/administrator/Documents/UploadedProjects/<user id>
export IPHONEOS_DEPLOYMENT_TARGET=7.0
export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk -L/Users/administrator/Documents/UploadedProjects/<user id>/Payload -L../../Libs -F/Users/administrator/Documents/UploadedProjects/<user id>/Payload -F../../Libs -filelist /Users/administrator/Documents/UploadedProjects/<user id>/build/B4iProject.build/Release-iphoneos/B4iProject.build/Objects-normal/armv7/result.LinkFileList -miphoneos-version-min=7.0 -ObjC -fobjc-arc -fobjc-link-runtime -lCore -framework Foundation -framework CoreGraphics -framework UIKit -liTableView -liMedia -liHttp -liJSON -liStringUtils -liBarcode -liHUD -liRandomAccessFile -lb4i_alipay -framework AVFoundation -lz -framework AlipaySDK -framework Foundation -framework QuartzCore -framework UIKit -framework CFNetwork -framework CoreGraphics -framework CoreMotion -framework CoreTelephony -framework CoreText -framework SystemConfiguration -lCore -lc++ -liDebug2 -Xlinker -dependency_info -Xlinker /Users/administrator/Documents/UploadedProjects/<user id>/build/B4iProject.build/Release-iphoneos/B4iProject.build/Objects-normal/armv7/result_dependency_info.dat -o /Users/administrator/Documents/UploadedProjects/<user id>/Payload/result.app/result
ld: library not found for -lb4i_alipay
clang: error: linker command failed with exit code 1 (use -v to see invocation)


I reference some issues and can't find the problem, did I make mistakes by create the lib or did I use it the wrong way? thanks very much

I'v checked the project in the object folder, the project contains the libb4i_alipay.a, but I got error above

:D I have done the following steps:
first, import the third party lib and it's depending framewrok, bundle into the project( including some .h/.m files and Util, openssl folders)
then I set the search path into the macserver/Libs folder, import iCore.h File ,and write code like this:

[[AlipaySDK defaultService] payOrder: orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
NSLog(@"reslut = %@",resultDic);
}];

then after generating a libb4i_alipay.lib , I use B4Ih2xml.jar and get a xml,
I put I into B4I project, but when I send It to server to builder the code , I get the error I first post
 

Ju Yang

Active Member
Licensed User
#import "iCore.h"

//~dependsOn:AlipaySDK.framework.3
//~dependson:Foundation.framework
//~dependson:QuartzCore.framework
//~dependson:UIKit.framework
//~dependson:CFNetwork.framework
//~dependson:CoreGraphics.framework
//~dependson:CoreMotion.framework
//~dependson:CoreTelephony.framework
//~dependson:CoreText.framework
//~dependson:SystemConfiguration.framework
//~dependson:libCore.dylib
//~dependson:libz.dylib
//~dependson:libc++.dylib
//~event: Finished
//~version:1.00
 

Alberto Iglesias

Well-Known Member
Licensed User
A little question about debugging Libraries for B4i:

How I can debug in XCODE a library for B4i? How instance this B4i object?


I try like this but not working:

B4X:
B4IMyObject* objmy;
[objmy Initialize:self :@"objmy"];
[objmy Show:self :self];


and in my Library I have like:

B4X:
-(void)Initialize:(B4I*)bi :(NSString *)EventName { }


Thanks in advance!
 

Alberto Iglesias

Well-Known Member
Licensed User
Anybody know how I can TEST the library directly in XCODE?

I need to instance my object created for B4i, and I need to know how create B4i Object

I try like this:

B4X:
    B4I *objBI = [[B4I alloc]init];
    B4IMYLIB *objMy = [[B4IMYLIB alloc]init];;
    [objMy Initialize:objB4I.bi :@"objMy"];

Then problem is: What is this object I need to pass? objB4I.bi is not correct! I think in B4iObjectWrapper but I don´t know how instance

How to get: self.bi?

Try this too but without success, using "B4IStaticModule"
B4X:
B4IStaticModule *objB4I = [[B4IStaticModulealloc]init];
B4IMYLIB *objmy = nil;
objmy = [B4IMYLIB new];
[objmy Initialize:objB4I.bi :@"objmy"];
 
Last edited:

Alberto Iglesias

Well-Known Member
Licensed User
Erel,

This is for debug my library in XCODE directly, without using B4i.

This parameter in B4i is automatically, but in XCODE, I can´t understand..

B4X:
B4I *objB4I = [[B4Ialloc]init];

and

[objmy Initialize:objB4I :@"objmy"];

Not work! When pass in Initialize, just in this line:
[B4IObjectWrappersetBIAndEventName:self :bi :EventName];

get this error

-[__NSCFConstantString ToLowerCase]: unrecognized selector sent to instance 0x100367010

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString ToLowerCase]: unrecognized selector sent to instance 0x100367010'
 

Alberto Iglesias

Well-Known Member
Licensed User
Erel,

I´m using the same library (crytografy) in two B4i Libraries, I need this because I use in both.

If I use one of other library in B4i works perfectly, but when I use this two libraries in the same B4i project I got:

duplicate symbol _kCommonCryptoErrorDomain in:
../../Libs/libiLicense.a(NSData+CommonCrypto.o)
../../Libs/libiComboBox.a(NSData+CommonCrypto.o)


How to ignore this error?

Thanks

Alberto Iglesias
 
Top