Previously we have implemented witness calculation in android native
Now, let’s do the same for iOS
Open our root ios folder in xCode and after indexing we will see:
scroll down and search for our module:
As we haven’t implemented our generated Spec file yet, the xCode will offer you to fix that:
To go to our spec file, you could just cmd+click on RnWtnscalcs implementation
Now let’s get back to our RnWtnscalcs.mm file and implement plus function
now, in android project, from the android studio, let’s remove “#include ” from rn-wtnscalcs.cpp if your file contains it, and move it to cpp-adapter.cpp if it not exists there
this include related only to android project and shouldn't be in common cpp file
And rebuild our project for ios:
npx expo prebuild --platform ios --clean && npx expo run:ios
after start running this command, ur xcode will offer you to re-save project, so wait till the generation ends, and click-re-save
Finally we got our functions works:
You could see familiar things here, e.g. WtnsUtils, or “dat” in datAssets.xcassets, but let’s get it step by step:
first things first - the library. And that is the most confusing part
We need a libgmp - the helper library, that our witnesscalc_auth depends on
move to out witnesscalc repo and open ./build_gmp.sh file
And here we have 2 options, both can run on device and simulator, but it depends on “which one" exactly, for example “ios” option is running only on devices and simulators on arm64 architecture, such as iPhone 15, 14, …etc, (and simulators too)
same thing for x86_64
In this guide we will test on iPhone 15 Pro simulator, so:
make ios
After compile - we will see freshly created build_witnesscalc_ios folder, and new subfolders under ./depends/gmp directory
chose your variant and copy to our module/wtnscalcs/cpp folder
we need to chose witnesscalc_authStatic variant:
Unfortunately we couldn’t chose “Any iOS simulator device” cuz it contains x86_64, and the libs we have compiled are not support it.
but for production you could build apropriate variants in witnesscalc repo and chose any iOS device(arm64).
So, let's run build for witnesscalc_authStatic and also “fr”
copy them to our ./modules/wtnscalcs/cpp folder next to libgmp.a file:
#ifndef bridge_h
#define bridge_h
#include "witnesscalc_auth.h"
#endif /* bridge_h */
it will let our iOS project access this libraries
Now, open root project ios folder in xCode and add new File to our module ios folder
open that file and press “add”(plus symbol at the bottom-left corner), chose Data Set
name it “authDat” as it shown above and drag-n-drop our auth.dat file inside, the same auth.dat file, which we use in android app, just copy it.
Now we need to configure our podspec file, so our changes and linking will not vanish out after each pod-install or app rebuild
So, our preparations done and we could move to the code:
Create WtnsUtils m and h files under ios folder as it shown above
#import <Foundation/Foundation.h>
#import "WtnsUtils.h"
@implementation WtnsUtils
static const NSUInteger ERROR_SIZE = 256;
static const unsigned long WITNESS_SIZE = 100 * 1024 * 1024;
+ (void)initialize {
if (self == [WtnsUtils self]) {
NSLog(@"WtnsUtils initialized");
}
}
+ (NSData *)calcWtnsAuth:(NSData *)privateInputsJson error:(NSError **)error {
NSBundle *bundle = [NSBundle bundleWithIdentifier:@"org.cocoapods.RnWtnscalcsDatAssets"];
// Check if bundle is loaded correctly
if (!bundle) {
NSLog(@"Bundle not found");
if (error) {
*error = [NSError errorWithDomain:@"WtnsUtilsErrorDomain" code:1 userInfo:@{NSLocalizedDescriptionKey: @"Resource bundle not found"}];
}
return nil;
}
// Attempt to load the data asset
NSDataAsset *authDat = [[NSDataAsset alloc] initWithName:@"authDat" bundle:bundle];
if (!authDat) {
NSLog(@"authDat file not found in bundle");
if (error) {
*error = [NSError errorWithDomain:@"WtnsUtilsErrorDomain" code:1 userInfo:@{NSLocalizedDescriptionKey: @"authDat file not found in bundle"}];
}
return nil;
}
return [self _calcWtnsAuth:authDat.data privateInputsJson:privateInputsJson error:error];
}
+ (NSData *)_calcWtnsAuth:(NSData *)descriptionFileData privateInputsJson:(NSData *)privateInputsJson error:(NSError **)error {
unsigned long *wtnsSize = (unsigned long *)malloc(sizeof(unsigned long));
*wtnsSize = WITNESS_SIZE;
char *wtnsBuffer = (char *)malloc(WITNESS_SIZE);
char *errorBuffer = (char *)malloc(ERROR_SIZE);
int result = witnesscalc_auth(
[descriptionFileData bytes], (unsigned long)[descriptionFileData length],
[privateInputsJson bytes], (unsigned long)[privateInputsJson length],
wtnsBuffer, wtnsSize,
errorBuffer, ERROR_SIZE);
if (result != WITNESSCALC_OK) {
[self handleWitnessError:result errorBuffer:errorBuffer wtnsSize:wtnsSize error:error];
free(wtnsSize);
free(wtnsBuffer);
free(errorBuffer);
return nil;
}
NSData *resultData = [NSData dataWithBytes:wtnsBuffer length:(NSUInteger)*wtnsSize];
free(wtnsSize);
free(wtnsBuffer);
free(errorBuffer);
return resultData;
}
+ (void)handleWitnessError:(int32_t)result errorBuffer:(char *)errorBuffer wtnsSize:(unsigned long *)wtnsSize error:(NSError **)error {
if (result == WITNESSCALC_ERROR) {
NSString *errorMessage = [[NSString alloc] initWithBytes:errorBuffer length:ERROR_SIZE encoding:NSUTF8StringEncoding];
if (errorMessage) {
errorMessage = [errorMessage stringByReplacingOccurrencesOfString:@"\0" withString:@""];
if (error) {
*error = [NSError errorWithDomain:@"com.example.WtnsUtils" code:result userInfo:@{NSLocalizedDescriptionKey: errorMessage}];
}
}
} else if (result == WITNESSCALC_ERROR_SHORT_BUFFER) {
NSString *errorMessage = [NSString stringWithFormat:@"Buffer too short, should be at least: %lu", *wtnsSize];
if (error) {
*error = [NSError errorWithDomain:@"com.example.WtnsUtils" code:result userInfo:@{NSLocalizedDescriptionKey: errorMessage}];
}
}
}
@end
as you see, we could access witnesscalc_auth method straight from .a library, cuz obj-c can interact with c++, so we don’t need any bindings and CMakeFiles like we did for android
and search for authDat asset, where our auth.dat file is.
note: that ur bundle identifier could be named differently
if you unsure, you could log all your bundle identifier and find the right one:
NSArray *bundles = [NSBundle allBundles];
for (NSBundle *bundle in bundles) {
NSLog(@"Bundle Identifier: %@", [bundle bundleIdentifier]);
}
Now, import WtnsUtils.h file in RnWtnscalcs.mm
- (void)generateAuthWtns:(NSString *)jsonInputsBase64 resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
NSError *error = nil;
// Convert base64 encoded string to NSData
NSData *jsonData = [[NSData alloc] initWithBase64EncodedString:jsonInputsBase64 options:0];
if (!jsonData) {
reject(@"error", @"Failed to decode base64 string", nil);
return;
}
NSData *result = [WtnsUtils calcWtnsAuth:jsonData error:&error];
if (error) {
NSLog(@"Error: %@", error.localizedDescription);
reject(@"error", error.localizedDescription, error);
} else {
// Encode result to base64 and resolve
NSString *resultBase64 = [result base64EncodedStringWithOptions:0];
resolve(resultBase64);
}
}
Now, rebuild the app, and run
npx expo prebuild --clean && npx pod-install && npx expo run:ios
SOCIAL SHARE CARD GENERATOR