Created
April 27, 2017 21:14
-
-
Save joenoon/ae7a71fb2f01bf9574edf041e764fd22 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Creates classes in Obj-C and Java that contain values from | |
# config.yaml (which can be overridden by ENV). | |
# Values are obfuscated. (Untested as to how secure this is, | |
# but the point is to do better than completely plain | |
# public api keys visible in builds/plists) | |
# The key value pairs can be accessed from React Native via: | |
# NativeModules.AppEnv.XYZ | |
# Need to change "MyApp" and "myapp" and make path adjustments | |
# as needed in your project. | |
# - Joe Noon ([email protected]) | |
require 'yaml' | |
require 'erb' | |
config = ENV["CONFIGURATION"] | |
yaml_filename = File.expand_path("config.yaml", File.dirname(__FILE__)) | |
yaml = YAML::load(ERB.new(IO.read(yaml_filename)).result) | |
env = {} | |
yaml.each_pair do |k,opts| | |
env[k] = (ENV[k] || opts[config]).to_s | |
if env[k] == "!" | |
raise "MISSING ENV['#{k}']" | |
end | |
end | |
env_filename = File.expand_path("ios/MyApp/AppEnv.h", File.dirname(__FILE__)) | |
output = %Q{ | |
@import UIKit; | |
#import "RCTBridgeModule.h" | |
@interface AppEnv : NSObject <RCTBridgeModule> | |
@property NSTimeInterval timeToParse; | |
@property NSMutableDictionary *env; | |
+ (instancetype)sharedInstance; | |
- (NSDictionary *)constantsToExport; | |
#{env.keys.map { |k| "- (NSString*)#{k};" }.join("\n")} | |
@end | |
} | |
File.open(env_filename, "w") do |f| | |
f.puts output | |
end | |
env_filename = File.expand_path("ios/MyApp/AppEnv.m", File.dirname(__FILE__)) | |
env_builders = [] | |
func_builders = [] | |
# each env var is put into a hash with value obfuscated. | |
# a comment is prepended for the developer with the unobfuscated value, but does not make it into the binary. | |
env.each_pair do |k,v| | |
v_ords = v.to_s.scan(/./).map { |x| x.ord } | |
if v_ords.any? | |
env_builders << %Q{ [_env setObject:[self getVal:(const char[])#{v_ords.inspect.sub("[", "{").sub("]", "}")} length:#{v_ords.size}] forKey:@#{k.inspect}]; } | |
else | |
env_builders << %Q{ [_env setObject:@"" forKey:@#{k.inspect}]; } | |
end | |
func_builders << "// #{k} #=> #{v.inspect}" | |
func_builders << "- (NSString*)#{k} { return [_env valueForKey:@#{k.inspect}]; }" | |
end | |
output = %Q{ | |
#import "RCTBridge.h" | |
#import "AppEnv.h" | |
@implementation AppEnv | |
RCT_EXPORT_MODULE() | |
@synthesize timeToParse = _timeToParse; | |
@synthesize env = _env; | |
@synthesize bridge = _bridge; | |
RCT_EXPORT_METHOD(reload) | |
{ | |
[_bridge reload]; | |
} | |
+ (instancetype)sharedInstance { | |
static AppEnv *_sharedInstance = nil; | |
static dispatch_once_t once_token; | |
dispatch_once(&once_token, ^{ | |
_sharedInstance = [AppEnv new]; | |
}); | |
return _sharedInstance; | |
} | |
- (instancetype)init | |
{ | |
if ((self = [super init])) { | |
_env = [NSMutableDictionary dictionary]; | |
NSDate* startTime = [NSDate date]; | |
#{env_builders.join("\n")} | |
//[_env setObject:[self getVal:(const char[]){ 115, 111, 109, 101, 116, 104, 105, 110, 103, 32, 110, 101, 119, 32, 104, 101, 114, 101, 33 } length:19] forKey:@"something"]; | |
NSDate* endTime = [NSDate date]; | |
_timeToParse = [endTime timeIntervalSinceDate:startTime]; | |
NSBundle* mainBundle = [NSBundle mainBundle]; | |
[_env setObject:[mainBundle bundleIdentifier] forKey:@"bundleIdentifier"]; | |
[_env setObject:[mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:@"longVersion"]; | |
[_env setObject:[mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"] forKey:@"shortVersion"]; | |
[_env setObject:UIApplicationOpenSettingsURLString forKey:@"UIApplicationOpenSettingsURLString"]; | |
} | |
return self; | |
} | |
- (NSString*)getVal:(const char *)bytes length:(int)length { | |
return [[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding]; | |
} | |
#{func_builders.join("\n")} | |
//- (NSString*)something { return [_env valueForKey:@"something"]; } | |
- (NSDictionary *)constantsToExport { return _env; } | |
@end | |
} | |
File.open(env_filename, "w") do |f| | |
f.puts output | |
end | |
env_filename = File.expand_path("android/app/src/main/java/com/MyApp/AppEnv.java", File.dirname(__FILE__)) | |
env_builders = [] | |
# each env var is put into a hash with value obfuscated. | |
# a comment is prepended for the developer with the unobfuscated value, but does not make it into the binary. | |
env.each_pair do |k,v| | |
v_ords = v.to_s.scan(/./).map { |x| x.ord } | |
env_builders << %Q{ // #{k}: #{v.inspect}} | |
env_builders << %Q{ this.env.put(#{k.inspect}, this.getVal(new byte[]#{v_ords.inspect.sub("[", "{").sub("]", "}")}));} | |
end | |
output = %Q{ | |
package com.myapp; | |
import android.widget.Toast; | |
import com.facebook.react.bridge.NativeModule; | |
import com.facebook.react.bridge.ReactApplicationContext; | |
import com.facebook.react.bridge.ReactContext; | |
import com.facebook.react.bridge.ReactContextBaseJavaModule; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import com.facebook.react.bridge.ReactMethod; | |
import java.util.Map; | |
import com.facebook.react.shell.MainReactPackage; | |
import java.util.List; | |
import java.io.UnsupportedEncodingException; | |
public class AppEnv extends ReactContextBaseJavaModule { | |
public Map<String, Object> env = new HashMap<>();; | |
public AppEnv(ReactApplicationContext reactContext) { | |
super(reactContext); | |
this.env.put("packageName", "com.myapp"); | |
this.env.put("longVersion", "1"); | |
this.env.put("shortVersion", "1"); | |
#{env_builders.join("\n")} | |
} | |
@Override | |
public String getName() { | |
return "AppEnv"; | |
} | |
@Override | |
public Map<String, Object> getConstants() { | |
return env; | |
} | |
public String getVal(byte[] bytes) { | |
String string = ""; | |
try | |
{ | |
string = new String(bytes, "UTF8"); | |
} | |
catch( UnsupportedEncodingException e) | |
{ | |
} | |
return string; | |
} | |
} | |
class AppEnvPackage extends MainReactPackage { | |
@Override | |
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { | |
List<NativeModule> modules = new ArrayList<>(); | |
modules.add(new AppEnv(reactContext)); | |
return modules; | |
} | |
} | |
} | |
File.open(env_filename, "w") do |f| | |
f.puts output | |
end | |
puts "***********************" | |
puts "* AppEnv constants *" | |
puts "***********************" | |
env.keys.sort.each do |k| | |
puts "#{k}: #{env[k]}" | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Example config.yaml use-cases | |
# Only keys here will make it into AppEnv. | |
# Env vars for the same keys will override values here. | |
SENTRY_DSN: | |
Debug: | |
Release: https://[email protected]/1 | |
APP_GIT_COMMIT: | |
Debug: | |
Release: # blank, so ENV["APP_GIT_COMMIT"] will be checked when building AppEnv | |
GOOGLE_TRACKING_ID: | |
Debug: UA-1 | |
Release: UA-2 | |
google_place_key: | |
Debug: ABC | |
Release: XYZ | |
graphqlURL: | |
Debug: http://localhost:3001/graphql | |
Release: https://api.productionurl/graphql |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment