Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Examples/HybridMobileDeployCompanion/iOS/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
*
* see http://facebook.github.io/react-native/docs/runningondevice.html
*/
jsCodeLocation = [HybridMobileDeploy appBundleUrl];

jsCodeLocation = [HybridMobileDeploy getBundleUrl];

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"HybridMobileDeployCompanion"
Expand Down
4 changes: 3 additions & 1 deletion Examples/HybridMobileDeployCompanion/iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.2.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand All @@ -38,5 +38,7 @@
<false/>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>CodePushDeploymentKey</key>
<string>deployment-key-here</string>
</dict>
</plist>
6 changes: 3 additions & 3 deletions Examples/HybridMobileDeployCompanion/index.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var {

var Button = require("react-native-button");

var HybridMobileDeploy = require('react-native-hybrid-mobile-deploy')('http://localhost:3000/', '<deployment key here>');
var HybridMobileDeploy = require('react-native-hybrid-mobile-deploy');

var HybridMobileDeployCompanion = React.createClass({
componentDidMount: function() {
Expand All @@ -30,15 +30,15 @@ var HybridMobileDeployCompanion = React.createClass({
return { update: false, updateString: "" };
},
handlePress: function() {
console.log("pressed");
HybridMobileDeploy.installUpdate(this.state.update);
},
render: function() {
var updateView;
if (this.state.update) {
updateView = (
<View>
<Text>Update Available: {'\n'} {this.state.update.scriptVersion} - {this.state.update.description}</Text>
<Button style={{color: 'green'}} onPress={this._handlePress}>
<Button style={{color: 'green'}} onPress={this.handlePress}>
Update
</Button>
</View>
Expand Down
5 changes: 3 additions & 2 deletions Examples/HybridMobileDeployCompanion/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"start": "node_modules/react-native/packager/packager.sh --root ../../"
},
"dependencies": {
"react-native": "^0.8.0-rc",
"react-native-button": "^1.2.0"
"react-native": "^0.8.0",
"react-native-button": "^1.2.0",
"react-native-hybrid-mobile-deploy": "file:../../"
}
}
29 changes: 24 additions & 5 deletions HybridMobileDeploy.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
#import "RCTBridgeModule.h"

@interface HybridMobileDeploy : NSObject <RCTBridgeModule>
+ (NSString *) getBundlePath:(NSString*)bundleName;
+ (NSURL *) getNativeBundleURL:(NSString*)bundleName;
+ (NSURL *)appBundleUrl;
+ (NSURL *)appBundleUrl:(NSString*)bundleName
nativeBundleName:(NSString*)nativeBundleName;

+ (NSURL *) getBundleUrl;

@end

@interface HybridMobileDeployConfig : NSObject

+ (void)setDeploymentKey:(NSString *)deploymentKey;
+ (NSString *)getDeploymentKey;

+ (void)setServerUrl:(NSString *)setServerUrl;
+ (NSString *)getServerUrl;

+ (void)setAppVersion:(NSString *)appVersion;
+ (NSString *)getAppVersion;

+ (void)setBuildVersion:(NSString *)buildVersion;
+ (NSString *)getBuildVersion;

+ (void)setRootComponent:(NSString *)rootComponent;
+ (NSString *)getRootComponent;

+ (NSDictionary *)getConfiguration;

@end
66 changes: 49 additions & 17 deletions HybridMobileDeploy.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,58 @@
var NativeHybridMobileDeploy = require('react-native').NativeModules.HybridMobileDeploy;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not generate JavaScript from TypeScript?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Native already uses its own JS transformation/bundling pipeline, which would be very tricky to integrate with TypeScript. Since the JS surface area is so small, I think it's preferable to leave it as plain JS rather than trying to force the React Native into something it wasn't designed for.

var requestFetchAdapter = require("./request-fetch-adapter.js");
var semver = require('semver');
var Sdk = require("hybrid-mobile-deploy-sdk/script/acquisition-sdk");
var serverUrl;
var appName;
var Sdk = require("hybrid-mobile-deploy-sdk/script/acquisition-sdk").AcquisitionManager;
var sdk;
var config;

var HybridMobileDeploy = {
queryUpdate: function(cb) {
var pkg = {nativeVersion: "1.2.3", scriptVersion: "1.2.0"};
sdk.queryUpdateWithCurrentPackage(pkg, cb);
},
installUpdate: function(update) {
NativeHybridMobileDeploy.installUpdateFromUrl(update.updateUrl, update.bundleName, (err) => console.log(err), () => console.log("success"));
function getConfiguration(callback) {
if (config) {
setImmediate(function() {
callback(/*error=*/ null, config);
});
} else {
NativeHybridMobileDeploy.getConfiguration(function(err, configuration) {
if (err) callback(err);
config = configuration;
callback(/*error=*/ null, config);
});
}
};
}

module.exports = function(serverUrl, deploymentKey, ignoreNativeVersion) {
sdk = new Sdk(requestFetchAdapter, {
serverUrl: serverUrl,
deploymentKey: deploymentKey,
ignoreNativeVersion: ignoreNativeVersion
function getSdk(callback) {
if (sdk) {
setImmediate(function() {
callback(/*error=*/ null, sdk);
});
} else {
getConfiguration(function(err, configuration) {
sdk = new Sdk(requestFetchAdapter, configuration);
callback(/*error=*/ null, sdk);
});
}
}

function queryUpdate(callback) {
getConfiguration(function(err, configuration) {
if (err) callback(err);
getSdk(function(err, sdk) {
if (err) callback(err);
var pkg = {appVersion: configuration.appVersion};
sdk.queryUpdateWithCurrentPackage(pkg, callback);
});
});
return HybridMobileDeploy;
}

function installUpdate(update) {
getConfiguration(function(err, config) {
NativeHybridMobileDeploy.installUpdateFromUrl(config.serverUrl + "acquire/" + config.deploymentKey, (err) => console.log(err));
});
}

var HybridMobileDeploy = {
getConfiguration: getConfiguration,
queryUpdate: queryUpdate,
installUpdate: installUpdate
};

module.exports = HybridMobileDeploy;
123 changes: 52 additions & 71 deletions HybridMobileDeploy.m
Original file line number Diff line number Diff line change
@@ -1,115 +1,96 @@
#import "HybridMobileDeploy.h"

#import "RCTBridgeModule.h"
#import "RCTRootView.h"
#import "RCTUtils.h"

@implementation HybridMobileDeploy

RCT_EXPORT_MODULE()

RCTBridge * _bridge;

@synthesize bridge = _bridge;

+ (NSString *) getBundleFolderPath
{
NSString* home = NSHomeDirectory();
NSString* bundleFolder = [home stringByAppendingPathComponent:@"HybridMobileDeploy"];
return bundleFolder;
}

+ (NSString *) getBundlePath:(NSString*)bundleName
+ (NSString *) getBundlePath
{
NSString * bundleFolderPath = [self getBundleFolderPath];
NSString* appBundleName = [bundleName stringByAppendingString:@".jsbundle"];
NSString* appBundleName = @"main.jsbundle";
return [bundleFolderPath stringByAppendingPathComponent:appBundleName];
}

+ (NSURL *) getNativeBundleURL:(NSString*)bundleName
+ (NSURL *) getNativeBundleURL
{
return [[NSBundle mainBundle] URLForResource:bundleName withExtension:@"jsbundle"];
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
}

+ (NSURL *) appBundleUrl
{
return [self appBundleUrl:@"bundle"
nativeBundleName:@"main"];
}

+ (NSURL *) appBundleUrl:(NSString*)bundleName
nativeBundleName:(NSString*)nativeBundleName
+ (NSURL *) getBundleUrl
{
NSFileManager *fileManager = [NSFileManager defaultManager];

NSString *bundlePath = [self getBundlePath:bundleName];
NSString *bundlePath = [self getBundlePath];
if ([fileManager fileExistsAtPath:bundlePath]) {
return [[NSURL alloc] initFileURLWithPath:bundlePath];
} else {
return [self getNativeBundleURL:nativeBundleName];
return [self getNativeBundleURL];
}
}

+ (void) loadBundle:(NSString*)moduleName
nativeBundleName:(NSString*)nativeBundleName
- (void) reloadBundle
{
dispatch_async(dispatch_get_main_queue(), ^{
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:[self appBundleUrl:moduleName nativeBundleName:nativeBundleName]
moduleName:moduleName
launchOptions:nil];

UIViewController *rootViewController = [[UIViewController alloc] init];
rootViewController.view = rootView;
[UIApplication sharedApplication].delegate.window.rootViewController = rootViewController;
self.bridge.bundleURL = [HybridMobileDeploy getBundleUrl];
[self.bridge reload];
});
}

RCT_EXPORT_METHOD(installUpdateFromUrl:(NSString*)updateUrl
bundleName:(NSString*)bundleName
nativeBundleName:(NSString*)nativeBundleName
failureCallback:(RCTResponseSenderBlock)failureCallback
successCallback:(RCTResponseSenderBlock)successCallback)
RCT_EXPORT_METHOD(getConfiguration:(RCTResponseSenderBlock)callback)
{
NSError *parameterError;
NSMutableDictionary *errorData;
if (!updateUrl) {
errorData = [NSMutableDictionary dictionary];
[errorData setValue:@"missing-updateUrl" forKey:NSLocalizedDescriptionKey];
} else if (!bundleName) {
errorData = [NSMutableDictionary dictionary];
[errorData setValue:@"missing-bundleName" forKey:NSLocalizedDescriptionKey];
}
callback(@[[NSNull null], [HybridMobileDeployConfig getConfiguration]]);
}

if (errorData) {
parameterError = [NSError errorWithDomain:@"HybridMobileDeploy"code:200 userInfo:errorData];
NSDictionary *rctError = RCTMakeError(@"Error with input to installUpdateFromUrl", parameterError, errorData);
failureCallback(@[rctError]);
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL* url = [NSURL URLWithString:updateUrl];
NSError *err;
RCT_EXPORT_METHOD(installUpdateFromUrl:(NSString*)updateUrl
callback:(RCTResponseSenderBlock)callback)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL* url = [NSURL URLWithString:updateUrl];
NSError *err;

NSString *updateContents = [[NSString alloc] initWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:&err];
if (err) {
failureCallback(@[err]);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSError *saveError;
NSString *bundleFolderPath = [HybridMobileDeploy getBundleFolderPath];
if (![[NSFileManager defaultManager] fileExistsAtPath:bundleFolderPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:bundleFolderPath withIntermediateDirectories:YES attributes:nil error:&saveError];
}
[updateContents writeToFile:[HybridMobileDeploy getBundlePath:bundleName]
atomically:YES
encoding:NSUTF8StringEncoding
error:&saveError];
if (saveError) {
failureCallback(@[saveError]);
} else {
[HybridMobileDeploy loadBundle:bundleName nativeBundleName:nativeBundleName];
successCallback(@[]);
}
});
}
});
}
NSString *updateContents = [[NSString alloc] initWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:&err];

if (err) {
// TODO send download url
callback(@[RCTMakeError(@"Error downloading url", err, [[NSDictionary alloc] initWithObjectsAndKeys:updateUrl,@"updateUrl", nil])]);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSError *saveError;
NSString *bundleFolderPath = [HybridMobileDeploy getBundleFolderPath];
if (![[NSFileManager defaultManager] fileExistsAtPath:bundleFolderPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:bundleFolderPath withIntermediateDirectories:YES attributes:nil error:&saveError];
}
[updateContents writeToFile:[HybridMobileDeploy getBundlePath]
atomically:YES
encoding:NSUTF8StringEncoding
error:&saveError];
if (saveError) {
// TODO send file path
callback(@[RCTMakeError(@"Error saving file", err, [[NSDictionary alloc] initWithObjectsAndKeys:[HybridMobileDeploy getBundlePath],@"bundlePath", nil])]);
} else {
[self reloadBundle];
callback(@[[NSNull null]]);
}
});
}
});
}

@end
4 changes: 4 additions & 0 deletions HybridMobileDeploy.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
13BE3DEE1AC21097009241FE /* HybridMobileDeploy.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* HybridMobileDeploy.m */; };
81D51F3A1B6181C2000DA084 /* HybridMobileDeployConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 81D51F391B6181C2000DA084 /* HybridMobileDeployConfig.m */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand All @@ -26,6 +27,7 @@
134814201AA4EA6300B7C361 /* libHybridMobileDeploy.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHybridMobileDeploy.a; sourceTree = BUILT_PRODUCTS_DIR; };
13BE3DEC1AC21097009241FE /* HybridMobileDeploy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HybridMobileDeploy.h; sourceTree = "<group>"; };
13BE3DED1AC21097009241FE /* HybridMobileDeploy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HybridMobileDeploy.m; sourceTree = "<group>"; };
81D51F391B6181C2000DA084 /* HybridMobileDeployConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HybridMobileDeployConfig.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -50,6 +52,7 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
81D51F391B6181C2000DA084 /* HybridMobileDeployConfig.m */,
13BE3DEC1AC21097009241FE /* HybridMobileDeploy.h */,
13BE3DED1AC21097009241FE /* HybridMobileDeploy.m */,
134814211AA4EA7D00B7C361 /* Products */,
Expand Down Expand Up @@ -112,6 +115,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
81D51F3A1B6181C2000DA084 /* HybridMobileDeployConfig.m in Sources */,
13BE3DEE1AC21097009241FE /* HybridMobileDeploy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Loading