com.wefitter.plugins.healthkit
Version:
Interact with the iOS HealthKit SDK and connects to the Wefitter server
477 lines (420 loc) • 16.2 kB
JavaScript
function WeFitterHealthKit() {
}
var matches = function(object, typeOrClass) {
return (typeof typeOrClass === 'string') ?
typeof object === typeOrClass : object instanceof typeOrClass;
};
var rounds = function(object, prop) {
var val = object[prop];
if (!matches(val, Date)) return;
object[prop] = Math.round(val.getTime() / 1000);
};
var hasValidDates = function(object) {
if (!matches(object.startDate, Date)) {
throw new TypeError("startDate must be a JavaScript Date Object");
}
if (!matches(object.endDate, Date)) {
throw new TypeError("endDate must be a JavaScript Date Object");
}
rounds(object, 'startDate');
rounds(object, 'endDate');
return object;
};
var getChecker = function(options) {
return function paramChecker(type) {
var value = options[type];
if (type === 'startDate' || type === 'endDate') {
if (!matches(value, Date)) throw new TypeError(type + ' must be a JavaScript Date');
} else if (type === 'samples') {
if (!Array.isArray(value)) throw new TypeError(type + ' must be a JavaScript Array');
} else {
if (!value) throw new TypeError('Missing required paramter ' + type);
}
};
};
// Supports:
// define('type');
// define('type', fn);
// define('type', obj);
// define('type', obj, fn)
var define = function(isPublic, runCordova, methodName, params, fn) {
if (params == null) params = {};
if (typeof params === 'function') {
fn = params;
params = {};
}
if (!fn) fn = Function.prototype;
var isEmpty = !!(params && params.noArgs);
var checks = params.required || [];
if (!Array.isArray(checks)) checks = [checks];
if (isEmpty) {
var result = function(callback, onError) {
cordova.exec(callback, onError, 'WeFitterHealthKit', methodName, []);
};
if (isPublic) {
WeFitterHealthKit.prototype[methodName] = result;
}
return result;
} else {
var result;
if (runCordova) {
result = function(options, callback, onError) {
if (!options) options = {};
try {
checks.forEach(getChecker(options));
fn(options);
} catch (error) {
onError(error.message);
}
var args = options ? [options] : [];
cordova.exec(callback, onError, 'WeFitterHealthKit', methodName, args);
};
} else {
result = function(options, callback, onError) {
if (!options) options = {};
try {
checks.forEach(getChecker(options));
fn(options, callback, onError);
} catch (error) {
onError(error.message);
}
};
}
if (isPublic) {
WeFitterHealthKit.prototype[methodName] = result;
}
return result;
};
};
var HealthKitCordova = {};
var WefitterHealthkitJSLib = {
active: true,
healthConnectionId: null,
cordovaHealthkitPlugin: HealthKitCordova,
API_URL: 'https://www.wefitter.com/api/v1/',
API_TOKEN: null,
AUTH_TOKEN: null,
setAPIURL: function(url) {
this.API_URL = url;
},
setAPIToken: function(apiToken) {
this.API_TOKEN = apiToken;
},
setAuthToken: function(authToken) {
this.AUTH_TOKEN = authToken;
},
setActive: function (value) {
if (value) {
this.active = true;
} else {
this.active = false;
}
},
setHealthConnectionId: function (id) {
this.healthConnectionId = id;
window.localStorage.setItem('healthConnectionId', JSON.stringify(id));
},
getHealthConnectionId: function () {
if (!this.healthConnectionId) {
this.healthConnectionId = window.localStorage.getItem('healthConnectionId');
}
return this.healthConnectionId;
},
isActive: function () {
return this.active;
},
getWorkouts: function () {
var _this = this;
return new Promise(
function(resolve, reject) {
_this.cordovaHealthkitPlugin.findWorkouts({},
function (result) {
resolve(result);
},
function (error) {
reject();
}
);
});
},
aggregatedSampleType: function (data) {
var _this = this;
return new Promise(
function(resolve, reject) {
_this.cordovaHealthkitPlugin.checkAuthStatus({
"type": data.sampleType
},
function (result) {
_this.cordovaHealthkitPlugin.querySampleTypeAggregated({
'startDate': data.startDate,
'endDate': data.endDate,
'aggregation': data.aggregation,
'sampleType': data.sampleType,
'unit': data.unit
},
function (result) {
resolve(result);
},
function (error) {
reject();
}
);
},
function () {
//don't have permission
reject();
}
);
}
);
},
parseDataObjectAjax: function (data) {
var query = '';
var dataKeys = Object.keys(data);
for (var i = 0; i < dataKeys.length; i++) {
var dataValue = ((typeof data[dataKeys[i]] === "object") && (data[dataKeys[i]] !== null)) ? JSON.stringify(
data[dataKeys[i]]) : data[dataKeys[i]];
query = query + dataKeys[i] + '=' + encodeURIComponent(dataValue);
if (i != dataKeys.length - 1) {
query = query + '&';
}
}
return query;
},
updateActivityData: function (sampleTypeData, callback, onError) {
var params = {
id: this.getHealthConnectionId(),
workouts: {
workouts: sampleTypeData.workouts || [],
daily: sampleTypeData.daily
}
};
var _this = this;
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 200) {
callback("data sent correctly");
} else {
// _this.consoleLog("data send failed");
onError("data send failed");
throw new Exception("data send failed");
}
}
}
request.open("POST", this.API_URL + 'connections/healthkit', true);
request.setRequestHeader('X-Wefitter-ApiToken', this.API_TOKEN);
request.setRequestHeader('X-Wefitter-Authorization',"Bearer " + this.AUTH_TOKEN);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send(this.parseDataObjectAjax(params));
},
run: function (options, callback, onError) {
var _this = this;
if (this.API_TOKEN == null || this.AUTH_TOKEN == null) {
onError("auth variables are undefined");
return;
}
if (!this.getHealthConnectionId()) {
// _this.consoleLog('asking to the sever for healthConnectionId');
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 200) {
// _this.consoleLog("data sent correctly");
_this.setHealthConnectionId(JSON.parse(request.response).content.id);
_this.continueRun(options.backendConfig, callback, onError);
} else {
// _this.consoleLog("data send failed");
onError("data send failed");
throw new Exception("data send failed");
}
}
}
request.open("GET", this.API_URL + "app/connections/22", true);
request.setRequestHeader('X-Wefitter-ApiToken', this.API_TOKEN);
request.setRequestHeader('X-Wefitter-Authorization',"Bearer " + this.AUTH_TOKEN);
request.send();
} else {
this.continueRun(options.backendConfig, callback, onError);
}
},
continueRun: function(noDefaultConfig, callback, onError) {
var _this = this;
// this.consoleLog('starting run...');
if (this.isActive()) {
// this.consoleLog('profile is active');
if (noDefaultConfig) {
this.getHealthkitConfig(function(data) {
_this.sendDataToServer(data, callback, onError);
}, callback, onError);
} else {
var sampleTypeList = [
{
key: 'workouts',
startDate: new Date(new Date().getTime() - 6 * 24 * 60 * 60 * 1000), // seven days ago
endDate: new Date(),
aggregation: 'day'
}, {
key: 'steps',
sampleType: 'HKQuantityTypeIdentifierStepCount',
unit: 'count',
startDate: new Date(new Date().getTime() - 6 * 24 * 60 * 60 * 1000),
endDate: new Date(),
aggregation: 'day'
}, {
key: 'calories',
sampleType: 'HKQuantityTypeIdentifierActiveEnergyBurned',
unit: 'kcal',
startDate: new Date(new Date().getTime() - 6 * 24 * 60 * 60 * 1000),
endDate: new Date(),
aggregation: 'day'
}, {
key: 'distance_walking',
sampleType: 'HKQuantityTypeIdentifierDistanceWalkingRunning',
unit: 'm',
startDate: new Date(new Date().getTime() - 6 * 24 * 60 * 60 * 1000),
endDate: new Date(),
aggregation: 'day'
}, {
key: 'distance_biking',
sampleType: 'HKQuantityTypeIdentifierDistanceCycling',
unit: 'm',
startDate: new Date(new Date().getTime() - 6 * 24 * 60 * 60 * 1000),
endDate: new Date(),
aggregation: 'day'
}
];
this.sendDataToServer(sampleTypeList, callback, onError);
}
} else {
callback("profile is not active");
// this.consoleLog("profile is not active")
}
},
sendDataToServer: function(typeList, callback, onError) {
var sampleTypeData = {};
var promises = [this.getWorkouts()];
for (var i = 1; i < typeList.length; i++) {
promises.push(this.aggregatedSampleType(typeList[i]))
}
var _this = this;
window.Promise.all(promises)
.then(function (values) {
// _this.consoleLog('connection done');
var dataToSend = {
workouts: values[0],
daily: {}
};
for (var index = 1; index < values.length; index++) {
if (values[index]) {
dataToSend.daily[typeList[index].key] = values[index];
}
}
_this.updateActivityData(dataToSend, callback, onError);
}, function (error) {
// _this.consoleLog('healthkit auth error');
onError("healthkit permissions error");
});
},
getHealthkitConfig: function(postfunc, callback, onError) {
var _this = this;
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 200) {
// _this.consoleLog("data get correctly");
var response = [];
var rawResponse = JSON.parse(request.response).content;
for (var i = 0; i < rawResponse.length; i++) {
var obj = {
key: rawResponse[i].key
};
if (rawResponse[i].params) {
var startDate = rawResponse[i].params.startDate;
startDate = startDate.split(' ');
var startDateDate = startDate[0].split(/\-/);
var startDateTime = startDate[1];
var startDateObject = new Date(startDateDate[0] + '/' + startDateDate[1] + '/' + startDateDate[2] + ' ' + startDateTime);
var endDate = rawResponse[i].params.endDate;
endDate = endDate.split(' ');
var endDateDate = endDate[0].split(/\-/);
var endDateTime = endDate[1];
var endDateObject = new Date(endDateDate[0] + '/' + endDateDate[1] + '/' + endDateDate[2] + ' ' + endDateTime);
obj.startDate = startDateObject;
obj.endDate = endDateObject;
obj.aggregation = rawResponse[i].params.aggregation;
obj.sampleType = rawResponse[i].params.sampleType;
obj.unit = rawResponse[i].params.unit;
}
response.push(obj);
}
postfunc(response);
} else {
// _this.consoleLog("data send failed");
onError("data send failed");
}
}
}
request.open("GET", this.API_URL + "app/connections/healthkit_config", true);
request.setRequestHeader('X-Wefitter-ApiToken', this.API_TOKEN);
request.setRequestHeader('X-Wefitter-Authorization',"Bearer " + this.AUTH_TOKEN);
request.send();
},
consoleLog: function(logString) {
if (typeof logString == "string") {
console.log("[wefitter-healthkit-plugin] " + logString);
} else {
console.log("[wefitter-healthkit-plugin]");
console.log(logString);
}
}
};
define(true, true, 'available', {noArgs: true});
define(true, false, 'run', WefitterHealthkitJSLib.run.bind(WefitterHealthkitJSLib));
define(true, false, 'setAPIURL', WefitterHealthkitJSLib.setAPIURL.bind(WefitterHealthkitJSLib));
define(true, false, 'setAPIToken', WefitterHealthkitJSLib.setAPIToken.bind(WefitterHealthkitJSLib));
define(true, false, 'setAuthToken', WefitterHealthkitJSLib.setAuthToken.bind(WefitterHealthkitJSLib));
HealthKitCordova.checkAuthStatus = define(false, true, 'checkAuthStatus');
HealthKitCordova.requestAuthorization = define(false, true, 'requestAuthorization');
HealthKitCordova.readDateOfBirth = define(false, true, 'readDateOfBirth', {noArgs: true});
HealthKitCordova.readGender = define(false, true, 'readGender', {noArgs: true});
HealthKitCordova.readFitzpatrickSkinType = define(false, true, 'readFitzpatrickSkinType', {noArgs: true});
HealthKitCordova.findWorkouts = define(false, true, 'findWorkouts');
HealthKitCordova.delete = define(false, true, 'delete');
HealthKitCordova.readWeight = define(false, true, 'readWeight');
HealthKitCordova.readHeight = define(false, true, 'readHeight');
HealthKitCordova.readBloodType = define(false, true, 'readBloodType', {noArgs: true});
HealthKitCordova.saveWeight = define(false, true, 'saveWeight', function(options) {
if (options.date == null) options.date = new Date();
if (typeof options.date === 'object') rounds(options, 'date');
});
HealthKitCordova.saveHeight = define(false, true, 'saveHeight', function(options) {
if (options.date == null) options.date = new Date();
if (typeof options.date === 'object') rounds(options, 'date');
});
HealthKitCordova.saveWorkout = define(false, true, 'saveWorkout', {required: 'startDate'}, function(options) {
var hasEnd = matches(options.endDate, Date);
var hasDuration = options.duration && options.duration > 0;
rounds(options, 'startDate');
if (!hasEnd && !hasDuration) {
throw new TypeError("endDate must be JavaScript Date Object, or the duration must be set");
}
if (hasEnd) rounds(options, 'endDate');
});
HealthKitCordova.monitorSampleType = define(false, true, 'monitorSampleType', {required: 'sampleType'});
HealthKitCordova.querySampleType = define(false, true, 'querySampleType', {required: 'sampleType'}, hasValidDates);
HealthKitCordova.querySampleTypeAggregated = define(false, true, 'querySampleTypeAggregated', {required: 'sampleType'}, hasValidDates);
HealthKitCordova.deleteSamples = define(false, true, 'deleteSamples', {required: 'sampleType'}, hasValidDates);
HealthKitCordova.queryCorrelationType = define(false, true, 'queryCorrelationType', {required: 'correlationType'}, hasValidDates);
HealthKitCordova.saveQuantitySample = define(false, true, 'saveQuantitySample', {required: 'sampleType'}, hasValidDates);
HealthKitCordova.saveCorrelation = define(false, true, 'saveCorrelation', {required: ['correlationType', 'samples']}, function(options) {
hasValidDates(options);
options.objects = options.samples.map(hasValidDates);
});
HealthKitCordova.sumQuantityType = define(false, true, 'sumQuantityType', {required: ['sampleType']}, hasValidDates);
WeFitterHealthKit.install = function() {
if (!window.plugins) window.plugins = {};
window.plugins.wefitterhealthkit = new WeFitterHealthKit();
return window.plugins.wefitterhealthkit;
};
cordova.addConstructor(WeFitterHealthKit.install);