I am trying to represent environment variables in the Salesforce codebase and came across Custom Metadata Types. So based on which Sandbox I am in, I want to vary the baseURL of an external service that I am hitting from my apex class. I want to avoid hard coding anything in the class, and hence trying to find out an environment variable like solution.
How would you represent the URL as a custom metadata type? Also, how can I access it in the class? What happens when a qa sandbox is refreshed from prod? Do they custom metadata type records get overridden?
How are you calling that external service? If it's truly a base url you might be better of using "named credential" for it. It'll abstract the base url away for you, include authentication or certificate if you have to present any...
Failing that - custom metadata might be a poor choice. They're kind of dictionary objects, you can add more (but not from apex) but if you deploy stuff using Git/Ant/SFDX CLI rather than changesets it'd become bit pain, you'd need different custom metadata value for sandbox vs prod. Kinda defeats the purpose.
You might be better off using custom setting instead (hierarchy is enabled by default, list you'd have to flip a checkbox in setup. List is useful if you need key-value kind of pairs, similar to custom metadata): https://salesforce.stackexchange.com/questions/74049/what-is-the-difference-between-custom-settings-and-custom-metadata-types
And you can modify them with Apex too. Which means that in ideal world you could have a "postcopy" class running as soon as sandbox is refreshed that overwrites the custom setting with the non-prod value. For named credential I don't think you can pull it off, you'd need a mini deployment that changes it or manual step (have you seen https://salesforce.stackexchange.com/q/955/799 ?)
I want to store some large offline data in user phone (more than 100 MB) in an encrypted database. If possible I also want to distribute the database pre-populated. I have also seen this.
I know about the webdatabase thing, but because it is depreciated, I am advised not to work with that.
I also have seen some third party plugins such as SQLite Plugin, but it works only for iOS and Android devices, but I target 4 platforms (ios, android, blackberry, windows)
Is there any other solution, other than writing down my own?
I made an app recently that required this, targetting the same OS's. You can use a combination of 2 databases :
1. LocalStorage ::
Check for localStorage
function supports_html5_storage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
Set an item into LocalStorage
localStorage.setItem("bar", foo);
or
localStorage["bar"] = foo;
Get an item from LocalStorage
var foo = localStorage.getItem("bar");
or
var foo = localStorage["bar"];
2. SQLite Database (more convenient, more persistive)
Set up your DB
var shortName = 'BHCAppDB';
var version = '1.0';
var displayName = 'BHCAppDB';
var maxSize = 65535;
if (!window.openDatabase){
alert('!! Databases are not supported in this Device !! \n\n We are sorry for the inconvenience and are currently working on a version that will work on your phone');
}
db = openDatabase(shortName, version, displayName,maxSize);
createAllTables(db);
Create your Tables
function createAllTables(db){
db.transaction(function(transaction){
transaction.executeSql("CREATE TABLE IF NOT EXISTS Profile(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT, gender TEXT,age INTEGER)");
}
Execute an SQL Query
transaction(function(transaction){
var rowCount = 'SELECT * FROM Profile';
transaction.executeSql(rowCount,[],function(transaction,result){
if(result.rows.length == 0){
var sqlString = 'INSERT INTO Profile (name,gender,age) VALUES("自己","Female",18)';
transaction.executeSql(sqlString);
}
});
});
EDIT :: I forgot to add in the last option :)
3. Native Storage on all devices
This is the best part of Phonegap. You can call a native plugin class on all the devices using the Phonegap plugin call. During the call, you can pass parameters to the class, and the native class can store your data in the OS itself.
For example :: in iOS, you create a plugin .h & .m class and register it with the Cordova.plist file. Once that's done, you need to send a call to the class from JavaScript using Phonegap. Once the parameters have been received using NSDictionary or any other NSArray type, you can call a CoreData class to store UNLIMITED amounts of data. You'll never run out of memory .
This can be done in a similar fashion for all the rest of the OS's also :)
For Encryption try the following :: SQLCipher
Here is some additional information on working with an existing SQLite database. In this example encrypted.db is that brand new database you create and pragma.
ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'secret'; -- create a new encrypted database
CREATE TABLE encrypted.t1(a,b); -- recreate the schema in the new database (you can inspect all objects using SELECT * FROM sqlite_master)
INSERT INTO encrypted.t1 SELECT * FROM t1; -- copy data from the existing tables to the new tables in the encrypted database
DETACH DATABASE encrypted;
In the W3C specification for webdatabase it is mentioned that the Web Applications Working Group continues work on two other storage-related specifications: Web Storage and Indexed Database API.
So the webdatabase specification is no longer active but the other two specifications are active.
The Web Storage can be used to store data locally within the user's browser. There are the following objects to achieve that:
localStorage which stores data without expiration date
sessionStorage which stores data for one session
The Web Storage is not recommended for your case (more than 100MB), because the W3C specification mentions that:
A mostly arbitrary limit of five megabytes per origin is recommended.
In my opinion SQLite is the best available option since it is a in-process library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine. Moreover the SQLite limits seems to cover your needs:
The largest possible setting for SQLITE_MAX_PAGE_COUNT is 2147483646. When used with the maximum page size of 65536, this gives a maximum SQLite database size of about 140 terabytes.
Regarding your encryption requirements you should consider the SQLCipher which is an SQLite extension.
SQLCipher is an SQLite extension that provides transparent 256-bit AES encryption of database files. To date, it has been open-sourced, sponsored and maintained by Zetetic LLC. In the mobile space, SQLCipher has enjoyed widespread use in Apple’s iOS, as well as Nokia / QT for quite some time.
An alternative option is to encrypt and decrypt your data when writing and reading your database.
I hope this helps.
The mobile app I am working on has a similar requirement. It requires offline access to a parts table that contains nearly 500,000 different parts in it. The source for this table is extracted from the server by getting its JSON via a well defined GET URL.
I considered Indexed DB but the mobile browsers inside iOS and Android don't support this. Web local storage is not an option because of its hard 5 MB limit. So, I decided to use the Web SQL Database standard (http://www.w3.org/TR/webdatabase/) even though its deprecated. My experience so far with using Web SQL Database has been very good. Database operations perform very well and are very reliable on the mobile devices I support (iPad 2, iPad 3, Motorola Xyboard, Samsung Galaxy Tab 2). Plus, Phonegap exposes a JavaScript API to work with this standard (see http://docs.phonegap.com/en/2.5.0/cordova_storage_storage.md.html#Storage).
I wrote a Java utility that converts the downloaded JSON data into a SQLite database whose files are packaged as part of the Android APK or the iOS app package.
When my Phonegap mobile app starts, it uses native code to check the app's private data directory for the presence of the SQLite database files. If the files are not present, the native code copies the database files from the app package.
My implementation is based on the sample code I found at the link below. I hope this helps. Let me know if you have any questions about my particular implementation.
http://gauravstomar.blogspot.com/2011/08/prepopulate-sqlite-in-phonegap.html
I tried using LokiJS as a local database, and found it helpful in non-relational data. In my case I retrieve a data stored using MongoDB on the server, but it depends on the nature of your system
See those questions/answers:
Opening and storing encrypted documents offline in iOS
Does PhoneGap / Apache Cordova propose an API for encrypted SQLite database
When using Mono Touch can I also package for a standard Window application?
I have made the mistake when starting the coding an iPhone App of not adding a prefix to my classnames, and as such have a conflict (A CoreData class called Category). The project build fine until the recent update of Xcode, and only now I realize the mistake.
Is it possible to rename CoreData classes while keeping a working system after update?
If I add a new version to the Datamodel and rename the class, the App updates, but it seems that the old table is deleted and a new (empty) one created. Obviously all the links subsequently are broken. I would like to maintain the data while making the change.
In Java EE you can overrule the table name if I remember correctly, and as such I could stick to the old class name to name the table. Is there any such possibility with CoreData?
Thanks in advance! I have to find a way to update the DB without all the Apps out in the field breaking.
Actually, it i documented quite well by Apple:
If you rename an entity or property,
you can set the renaming identifier in
the destination model to the name of
the corresponding property or entity
in the source model. You typically set
the renaming identifier using the
Xcode Data Modeling tool, (for either
an NSEntityDescription or an
NSPropertyDescription object). In
Xcode, the renaming identifier is in
the User Info pane of the Detail Pane,
below the version hash modifier (see
The Browser View in Xcode Tools for
Core Data). (Mac OS X Developer Library )
But actually for me it seems to work just to change the Classname and leave the rest of the model alone.
I'm trying to launch a SL4 OOB application from the web browser. I'm currently trying to achieve this by associating a file type with sllauncher.exe and then adding the SL4 OOB application id as a parameter. The SL4 OOB application is launched when the specific file type is downloaded from the browser, but in order for me to create an installer I need to be able to retrieve the application id so I can update the registry entry for the file type association.Does anyone know how the application id is generated or if it's possible to force a specific application id to be used?
I fear that this won't be easy...
There's a method Deployment.GetAppIdForUri which sounds like it does exactly what you need, but unfortunately it is marked SecurityCritical so you can't use it.
A hack that might work is this:
When the app is installed OOB, you might use Application.Current.Host.Source or something like that plus a bit of substring magic to get the app ID. Unfortunately, I'm not able to test that right now because I'm uninstalling the VS2010 RC on this machine right now ;-)
Anyway, if that works, you might take the ID and write it into IsoStore for later use.
Forcing a specific ID for the app would be nice, but I think it's not possible.
Cheers, Alex
The shortcut file of Silverlight OOB application includes the application id. Retrieving the application id from the shortcut file is work to me.
I wonder about dynamically changing of class name in .NET application. For example WindowsForms10.SysTreeView32.app.0.19fd5c7. The last string "19fd5c7" would change, but I don't know what makes it changing. Is it the version, the GUI modification, environment, OS or what?
Thanks.
It's actually based on the hash code of the current app domain.