Skip to content

Commit

Permalink
Merge commit '59c5dc7a27151116b9d9e996fe27df3a90b7e81f'
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Canevese committed Nov 22, 2023
2 parents f9b7c82 + 59c5dc7 commit 36c36c0
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 75 deletions.
18 changes: 9 additions & 9 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/* eslint-disable */
/* eslint-disable */
import * as React from 'react';
import { StyleSheet, Text, ImageBackground } from 'react-native';
import { checkAndReplaceBundle } from '../../src';

export default function App() {
React.useEffect(() => {
async function startApp() {
await checkAndReplaceBundle('9980a7943e0db5892b50f6972b02b4c2a2b3');
console.log('loaded app');
}
startApp();
}, []);
// React.useEffect(() => {
// async function startApp() {
// await checkAndReplaceBundle('70df8a199213d53d892a3eddb6f3bf9c4158');
// console.log('loaded app');
// }
// startApp();
// }, []);
return (
<ImageBackground
style={styles.container}
Expand All @@ -22,7 +22,7 @@ export default function App() {
opacity: 0,
}}
>
<Text>ciao alessio come stai?</Text>
<Text>ciao hello stai?</Text>
</ImageBackground>
);
}
Expand Down
1 change: 1 addition & 0 deletions ios/BundleUpdater.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
reject:(void (^)(NSString *, NSString *, NSError *))reject;
- (NSURL *)initializeBundle:(RCTBridge *)bridge withKey:(NSString *)key;
- (void)reload;
- (void)checkAndReplaceBundle: (nullable NSString *)apiKey;
#endif

@end
211 changes: 147 additions & 64 deletions ios/BundleUpdater.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,23 @@
#import <React/RCTBundleURLProvider.h>
#import <React/RCTReloadCommand.h>

@implementation BundleUpdater
@interface BundleUpdater()
// in this case variables would be visible for anyone which has an instance of the class
// @property (nonatomic, strong) NSString *apiUrl;
// @property (nonatomic, strong) NSString *bundle_id_from_api;
// @property (nonatomic, strong) BundleUpdaterBottomSheetViewController *bottomSheetVC;
@end

@implementation BundleUpdater{
// in this case are private variables only visible inside the class
NSString *_apiUrl;
NSString *_bundle_id_from_api;
BundleUpdaterBottomSheetViewController *_bottomSheetVC;
}
@synthesize bridge = _bridge;

RCT_EXPORT_MODULE()

NSString *apiUrl = @"http://192.168.10.37:3003";
NSDictionary *update_config = @{};

+ (instancetype)sharedInstance{
static BundleUpdater *sharedInstance = nil;
static dispatch_once_t once_token;
Expand All @@ -28,9 +37,20 @@ + (instancetype)sharedInstance{

- (instancetype)init{
self = [super init];
// init variables
_apiUrl = @"http://192.168.0.102:3003";
_bundle_id_from_api = @"";
_bottomSheetVC = [[BundleUpdaterBottomSheetViewController alloc] init];
return self;
}

/*!
* @brief get the hash of the file
*
* @param script - data of the bundle
* *
* @return a data hash
*/
- (NSMutableData *)calculateSHA256Hash:(NSData *)script {
NSMutableData *hash =
[NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
Expand All @@ -39,6 +59,11 @@ - (NSMutableData *)calculateSHA256Hash:(NSData *)script {
return hash;
}

/*!
* @brief load the saved hash of the file from disk
*
* @return a string hash of the file
*/
- (NSString *)loadHashFromDisk {
NSString *hashPath = [[NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
Expand All @@ -49,11 +74,15 @@ - (NSString *)loadHashFromDisk {
return oldHash;
}

/*!
* @brief save the new bundle and the hash on disk
*
* @param script - data of bundle
*
* @param hashString - the hash of the bundle file
*/
- (void)saveNewBundleAndHashToDisk:(NSData *)script
hashString:(NSString *)hashString {
// Save the bundle on a folder with the sdk key as path
// NSString *folder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
// NSFileManager *manager = [NSFileManager defaultManager];
NSString *scriptPath = [[NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:@"main.jsbundle"];
Expand All @@ -68,30 +97,23 @@ - (void)saveNewBundleAndHashToDisk:(NSData *)script
error:nil];
}

/*!
* @brief get the device model info
*
* @return a string with the info of the device
*/
- (NSString *)getDeviceModelName {
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}

- (void)getPhoneBatteryLevel {
// UIDevice *device = [UIDevice currentDevice];
// [device setBatteryMonitoringEnabled:YES];
// switch ([device batteryState]) {
// case UIDeviceBatteryStateCharging:
// return @"Charging";
// case UIDeviceBatteryStateFull:
// return @"Charge complete";
// case UIDeviceBatteryStateUnplugged:
// return @"Unplugged";
// case UIDeviceBatteryStateUnknown:
// return @"Unknown";
// }

// return @"Unknown";
}

/*!
* @brief get the a list of info as summary for the device
*
* @return a dictionary with the info
*/
- (NSDictionary *)getMetaData {
UIDevice *device = [UIDevice currentDevice];
NSString *device_name = device.name;
Expand All @@ -100,15 +122,14 @@ - (NSDictionary *)getMetaData {
NSString *systemVersion = device.systemVersion;
NSString *deviceIdentifier = [[device identifierForVendor] UUIDString];
NSString *bundleID = NSBundle.mainBundle.bundleIdentifier;

NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *marketingVersion = infoDictionary[@"CFBundleShortVersionString"];
NSString *projectVersion = infoDictionary[@"CFBundleVersion"];

NSString *preferredUserLocale =
[[[NSBundle mainBundle] preferredLocalizations] firstObject];
NSString *batteryLevel = @"Unknown";
// NSString *phoneChargingState = [self getPhoneBatteryLevel];
// TODO NSString *phoneChargingState = [self getPhoneBatteryLevel];
// if (![phoneChargingState isEqualToString:@"Unknown"]) {
// batteryLevel = [NSString
// stringWithFormat:@"%.f", (float)[device batteryLevel] * 100];
Expand All @@ -121,12 +142,10 @@ - (NSDictionary *)getMetaData {
#ifdef DEBUG
buildMode = @"DEBUG";
#endif

float scaleFactor = [[UIScreen mainScreen] scale];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;

return @{
@"device_name" : device_name,
@"device_model" : device_model,
Expand All @@ -151,32 +170,45 @@ - (NSDictionary *)getMetaData {
};
}

/*!
* @brief show the update bottomsheet if the config are supplied
*
* @param updateData - dictionary with the sheet config
*/
- (void)showBottomSheet:(NSDictionary *)updateData {
BundleUpdaterBottomSheetViewController *bottomSheetVC =
[[BundleUpdaterBottomSheetViewController alloc] init];

// Set the data properties of the bottom sheet view controller
bottomSheetVC.image = updateData[@"image"];
bottomSheetVC.titleText = updateData[@"title"];
;
bottomSheetVC.message = updateData[@"message"];
bottomSheetVC.buttonLabel = updateData[@"button_label"];
bottomSheetVC.buttonLink = updateData[@"button_label"];
bottomSheetVC.buttonBackgroundColor = updateData[@"button_color"];
bottomSheetVC.buttonIcon = [UIImage imageNamed:@"button_icon"];
bottomSheetVC.footerLogo = [UIImage imageNamed:@"sdk_logo"];

_bottomSheetVC.image = updateData[@"image"];
_bottomSheetVC.titleText = updateData[@"title"];
_bottomSheetVC.message = updateData[@"message"];
_bottomSheetVC.buttonLabel = updateData[@"button_label"];
_bottomSheetVC.buttonLink = updateData[@"button_label"];
_bottomSheetVC.buttonBackgroundColor = updateData[@"button_color"];
_bottomSheetVC.buttonIcon = [UIImage imageNamed:@"button_icon"];
_bottomSheetVC.footerLogo = [UIImage imageNamed:@"sdk_logo"];
UIViewController *rootViewController =
[[[UIApplication sharedApplication] keyWindow] rootViewController];

bottomSheetVC.modalPresentationStyle = UIModalPresentationOverFullScreen;
bottomSheetVC.transitioningDelegate = self;

[rootViewController presentViewController:bottomSheetVC
_bottomSheetVC.modalPresentationStyle = UIModalPresentationOverFullScreen;
_bottomSheetVC.transitioningDelegate = self;
[rootViewController presentViewController:_bottomSheetVC
animated:YES
completion:nil];
}

/*!
* @brief hide the bottomsheet*
*/
-(void)hideBottomSheet {
dispatch_async(dispatch_get_main_queue(), ^{
[self->_bottomSheetVC dismissViewControllerAnimated:YES completion:nil];
});
}


/*!
* @brief Initialize the app with the apikey | get the configuration for the sheet/app
*
* @param apiKey - the apiKey for the app
*/
- (void)initialization:(NSString *)apiKey
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
Expand All @@ -187,7 +219,7 @@ - (void)initialization:(NSString *)apiKey
NSString *savedBundle = [[NSUserDefaults standardUserDefaults]
stringForKey:@"bundleId"];
NSString *urlString =
[NSString stringWithFormat:@"%@/project/%@/initialize", apiUrl, apiKey];
[NSString stringWithFormat:@"%@/project/%@/initialize", _apiUrl, apiKey];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
Expand Down Expand Up @@ -262,26 +294,37 @@ - (void)initialization:(NSString *)apiKey
return;
}
NSLog(@"%@", responseDict.description);
@try {
if ([responseDict valueForKey:@"update_required"]) {
// Pass the "update_required" object to the showBottomSheet
// method
update_config = [responseDict valueForKey:@"update_required"];
NSString *bundle_id = [responseDict valueForKey:@"bundleId"];
[[NSUserDefaults standardUserDefaults] setObject:bundle_id forKey:@"bundleId"];
// dispatch_async(dispatch_get_main_queue(), ^{
// [self showBottomSheet:responseDict[@"update_required"]];
// });
NSLog(@"%@", [responseDict valueForKey:@"update_required"]);
id updateRequiredValue = [responseDict valueForKey:@"update_required"];
if (updateRequiredValue != nil) {
if([updateRequiredValue isKindOfClass:[NSNumber class]]){
// update not required
}else{
//update required
if ([responseDict valueForKey:@"update_required"]) {
//update_config = [responseDict valueForKey:@"update_required"];
self->_bundle_id_from_api = [responseDict valueForKey:@"bundleId"];
dispatch_async(dispatch_get_main_queue(), ^{
[self showBottomSheet:updateRequiredValue];
});
}
}
} @catch (NSException *exception) {
NSLog(@"Update not required");
}
}
}];

[dataTask resume];
}

/*!
* @brief Initialize the bundle for react native
*
* @param bridge - the react native bridge to start the app
*
* @param key - the apiKey for the app
*
* @return a bundle for the react native app
*/
- (NSURL *)initializeBundle:(RCTBridge *)bridge withKey:(NSString *)key{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings]
Expand Down Expand Up @@ -325,12 +368,22 @@ - (NSURL *)initializeBundle:(RCTBridge *)bridge withKey:(NSString *)key{
#endif
}

RCT_EXPORT_METHOD(checkAndReplaceBundle : (NSString *)apiKey) {
/*!
* @brief Check the bundle hash if it's the same and open the bottomsheet if not
*
* @param apiKey - the api key of the project
*/
RCT_EXPORT_METHOD(checkAndReplaceBundle : (nullable NSString *)apiKey) {
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Save the actual bundle id on the phone
[[NSUserDefaults standardUserDefaults] setObject:self->_bundle_id_from_api forKey:@"bundleId"];
// get the saved api key
NSString *_key = [[NSUserDefaults standardUserDefaults] stringForKey:@"bundleKey"];
NSString *keyToUse = apiKey ? apiKey : _key;
// Fetch script from server
NSString *url = [NSString
stringWithFormat:@"%@/project/%@/bundle", apiUrl, apiKey];
stringWithFormat:@"%@/project/%@/bundle", self->_apiUrl, keyToUse];

NSLog(@"[SDK] Fetching script from %@", url);

Expand Down Expand Up @@ -387,12 +440,21 @@ - (NSURL *)initializeBundle:(RCTBridge *)bridge withKey:(NSString *)key{
[self saveNewBundleAndHashToDisk:script
hashString:hashString];
NSLog(@"[SDK] SAVED NEW BUNDLE CORRECTLY");
dispatch_async(dispatch_get_main_queue(), ^{
[self showBottomSheet:update_config];
});
[self reload];
} else {
NSLog(@"[SDK] BUNDLE IS UP TO DATE");
}
// update done or not - dismiss bottomsheet
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.2 animations:^{
self->_bottomSheetVC.backgroundView.alpha = 0;
}];
[NSTimer scheduledTimerWithTimeInterval:0.2
target:self
selector:@selector(hideBottomSheet)
userInfo:nil
repeats:NO];
});
} else {
// An error occurred during the download. Handle it
// here.
Expand All @@ -412,6 +474,9 @@ - (NSURL *)initializeBundle:(RCTBridge *)bridge withKey:(NSString *)key{
});
}

/*!
* @brief reload the bundle for the javascript section
*/
RCT_EXPORT_METHOD(reload) {
dispatch_async(dispatch_get_main_queue(), ^{
RCTTriggerReloadCommandListeners(@"bundle changed");
Expand All @@ -427,4 +492,22 @@ - (NSURL *)initializeBundle:(RCTBridge *)bridge withKey:(NSString *)key{
}
#endif


#pragma mark - TO IMPLEMENT:
//- (void)getPhoneBatteryLevel {
// UIDevice *device = [UIDevice currentDevice];
// [device setBatteryMonitoringEnabled:YES];
// switch ([device batteryState]) {
// case UIDeviceBatteryStateCharging:
// return @"Charging";
// case UIDeviceBatteryStateFull:
// return @"Charge complete";
// case UIDeviceBatteryStateUnplugged:
// return @"Unplugged";
// case UIDeviceBatteryStateUnknown:
// return @"Unknown";
// }

// return @"Unknown";
//}
@end
Loading

0 comments on commit 36c36c0

Please sign in to comment.