mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-14 18:12:09 +08:00
feat(Utils): dataSerialize, dataDeserialize, numberHasDecimals, numberIs64Bit
This commit is contained in:
8
packages/core/index.d.ts
vendored
8
packages/core/index.d.ts
vendored
@ -105,8 +105,8 @@ export type { InstrumentationMode, TimerInfo } from './profiling';
|
||||
export { encoding } from './text';
|
||||
export * from './trace';
|
||||
export * from './ui';
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString, dismissSoftInput, queueMacrotask, queueGC, throttle, debounce } from './utils';
|
||||
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback } from './utils/types';
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString, dismissSoftInput, queueMacrotask, queueGC, throttle, debounce, dataSerialize, dataDeserialize } from './utils';
|
||||
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback, numberHasDecimals, numberIs64Bit } from './utils/types';
|
||||
export declare const Utils: {
|
||||
GC: typeof GC;
|
||||
RESOURCE_PREFIX: string;
|
||||
@ -134,6 +134,10 @@ export declare const Utils: {
|
||||
android: typeof androidUtils;
|
||||
ad: typeof androidUtils;
|
||||
ios: typeof iosUtils;
|
||||
dataSerialize: typeof dataSerialize;
|
||||
dataDeserialize: typeof dataDeserialize;
|
||||
numberHasDecimals: typeof numberHasDecimals;
|
||||
numberIs64Bit: typeof numberIs64Bit;
|
||||
setTimeout: typeof setTimeout;
|
||||
setInterval: typeof setInterval;
|
||||
clearInterval: typeof clearInterval;
|
||||
|
@ -137,8 +137,8 @@ export * from './trace';
|
||||
|
||||
export * from './ui';
|
||||
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, queueMacrotask, queueGC, debounce, throttle, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString, dismissSoftInput } from './utils';
|
||||
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback } from './utils/types';
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, executeOnUIThread, queueMacrotask, queueGC, debounce, throttle, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString, dismissSoftInput, dataDeserialize, dataSerialize } from './utils';
|
||||
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback, numberHasDecimals, numberIs64Bit } from './utils/types';
|
||||
|
||||
export const Utils = {
|
||||
GC,
|
||||
@ -170,6 +170,10 @@ export const Utils = {
|
||||
// legacy (a lot of plugins use the shorthand "ad" Utils.ad instead of Utils.android)
|
||||
ad: androidUtils,
|
||||
ios: iosUtils,
|
||||
dataSerialize,
|
||||
dataDeserialize,
|
||||
numberHasDecimals,
|
||||
numberIs64Bit,
|
||||
setTimeout,
|
||||
setInterval,
|
||||
clearInterval,
|
||||
|
@ -1,5 +1,143 @@
|
||||
import { getNativeApplication, android as androidApp } from '../application';
|
||||
import { Trace } from '../trace';
|
||||
import { numberHasDecimals, numberIs64Bit } from './types';
|
||||
|
||||
export function dataDeserialize(nativeData?: any) {
|
||||
if (nativeData === null || typeof nativeData !== 'object') {
|
||||
return nativeData;
|
||||
}
|
||||
let store;
|
||||
|
||||
switch (nativeData.getClass().getName()) {
|
||||
case 'java.lang.String': {
|
||||
return String(nativeData);
|
||||
}
|
||||
|
||||
case 'java.lang.Boolean': {
|
||||
return String(nativeData) === 'true';
|
||||
}
|
||||
|
||||
case 'java.lang.Float':
|
||||
case 'java.lang.Integer':
|
||||
case 'java.lang.Long':
|
||||
case 'java.lang.Double':
|
||||
case 'java.lang.Short': {
|
||||
return Number(nativeData);
|
||||
}
|
||||
|
||||
case 'org.json.JSONArray': {
|
||||
store = [];
|
||||
for (let j = 0; j < nativeData.length(); j++) {
|
||||
store[j] = dataDeserialize(nativeData.get(j));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'org.json.JSONObject': {
|
||||
store = {};
|
||||
let i = nativeData.keys();
|
||||
while (i.hasNext()) {
|
||||
let key = i.next();
|
||||
store[key] = dataDeserialize(nativeData.get(key));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'androidx.collection.SimpleArrayMap': {
|
||||
const count = nativeData.size();
|
||||
for (let l = 0; l < count; l++) {
|
||||
const key = nativeData.keyAt(l);
|
||||
store[key] = dataDeserialize(nativeData.get(key));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'androidx.collection.ArrayMap':
|
||||
case 'android.os.Bundle':
|
||||
case 'java.util.HashMap':
|
||||
case 'java.util.Map': {
|
||||
store = {};
|
||||
const keys = nativeData.keySet().toArray();
|
||||
for (let k = 0; k < keys.length; k++) {
|
||||
const key = keys[k];
|
||||
store[key] = dataDeserialize(nativeData.get(key));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (typeof nativeData === 'object' && nativeData instanceof java.util.List) {
|
||||
const array = [];
|
||||
const size = nativeData.size();
|
||||
for (let i = 0, n = size; i < n; i++) {
|
||||
array[i] = dataDeserialize(nativeData.get(i));
|
||||
}
|
||||
store = array;
|
||||
} else {
|
||||
store = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
export function dataSerialize(data?: any, wrapPrimitives?: boolean) {
|
||||
let store;
|
||||
switch (typeof data) {
|
||||
case 'string':
|
||||
case 'boolean': {
|
||||
if (wrapPrimitives) {
|
||||
if (typeof data === 'string') {
|
||||
return new java.lang.String(data);
|
||||
}
|
||||
return new java.lang.Boolean(data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
case 'number': {
|
||||
const hasDecimals = numberHasDecimals(data);
|
||||
if (numberIs64Bit(data)) {
|
||||
if (hasDecimals) {
|
||||
return java.lang.Double.valueOf(data);
|
||||
} else {
|
||||
return java.lang.Long.valueOf(data);
|
||||
}
|
||||
} else {
|
||||
if (hasDecimals) {
|
||||
return java.lang.Float.valueOf(data);
|
||||
} else {
|
||||
return java.lang.Integer.valueOf(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case 'object': {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data instanceof Date) {
|
||||
return new java.util.Date(data.getTime());
|
||||
}
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
store = new java.util.ArrayList();
|
||||
data.forEach((item) => store.add(dataSerialize(item, wrapPrimitives)));
|
||||
return store;
|
||||
}
|
||||
|
||||
if (data.native) {
|
||||
return data.native;
|
||||
}
|
||||
|
||||
store = new java.util.HashMap();
|
||||
Object.keys(data).forEach((key) => store.put(key, dataSerialize(data[key], wrapPrimitives)));
|
||||
return store;
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// We are using "ad" here to avoid namespace collision with the global android object
|
||||
export namespace ad {
|
||||
|
11
packages/core/utils/native-helper.d.ts
vendored
11
packages/core/utils/native-helper.d.ts
vendored
@ -1,3 +1,14 @@
|
||||
/**
|
||||
* Data serialization from JS > Native
|
||||
* @param wrapPrimitives Optionally wrap primitive types (Some APIs may require this)
|
||||
*/
|
||||
export function dataSerialize(data?: any, wrapPrimitives?: boolean): any;
|
||||
/**
|
||||
* Data deserialization from Native > JS
|
||||
* @param nativeData Native platform data
|
||||
*/
|
||||
export function dataDeserialize(nativeData?: any): any;
|
||||
|
||||
/**
|
||||
* Module with android specific utilities.
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Trace } from '../trace';
|
||||
import { getClass, isNullOrUndefined } from './types';
|
||||
import { getClass, isNullOrUndefined, numberHasDecimals, numberIs64Bit } from './types';
|
||||
|
||||
declare let UIImagePickerControllerSourceType: any;
|
||||
|
||||
@ -25,6 +25,88 @@ function openFileAtRootModule(filePath: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function dataDeserialize(nativeData?: any) {
|
||||
if (isNullOrUndefined(nativeData)) {
|
||||
// some native values will already be js null values
|
||||
// calling types.getClass below on null/undefined will cause crash
|
||||
return null;
|
||||
} else {
|
||||
switch (getClass(nativeData)) {
|
||||
case 'NSNull':
|
||||
return null;
|
||||
case 'NSMutableDictionary':
|
||||
case 'NSDictionary':
|
||||
let obj = {};
|
||||
const length = nativeData.count;
|
||||
const keysArray = nativeData.allKeys as NSArray<any>;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const nativeKey = keysArray.objectAtIndex(i);
|
||||
obj[nativeKey] = dataDeserialize(nativeData.objectForKey(nativeKey));
|
||||
}
|
||||
return obj;
|
||||
case 'NSMutableArray':
|
||||
case 'NSArray':
|
||||
let array = [];
|
||||
const len = nativeData.count;
|
||||
for (let i = 0; i < len; i++) {
|
||||
array[i] = dataDeserialize(nativeData.objectAtIndex(i));
|
||||
}
|
||||
return array;
|
||||
default:
|
||||
return nativeData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function dataSerialize(data: any, wrapPrimitives: boolean = false) {
|
||||
switch (typeof data) {
|
||||
case 'string':
|
||||
case 'boolean': {
|
||||
return data;
|
||||
}
|
||||
case 'number': {
|
||||
const hasDecimals = numberHasDecimals(data);
|
||||
if (numberIs64Bit(data)) {
|
||||
if (hasDecimals) {
|
||||
return NSNumber.alloc().initWithDouble(data);
|
||||
} else {
|
||||
return NSNumber.alloc().initWithLongLong(data);
|
||||
}
|
||||
} else {
|
||||
if (hasDecimals) {
|
||||
return NSNumber.alloc().initWithFloat(data);
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case 'object': {
|
||||
if (data instanceof Date) {
|
||||
return NSDate.dateWithTimeIntervalSince1970(data.getTime() / 1000);
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return NSArray.arrayWithArray((<any>data).map(dataSerialize));
|
||||
}
|
||||
|
||||
let node = {} as any;
|
||||
Object.keys(data).forEach(function (key) {
|
||||
let value = data[key];
|
||||
node[key] = dataSerialize(value, wrapPrimitives);
|
||||
});
|
||||
return NSDictionary.dictionaryWithDictionary(node);
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace iOSNativeHelper {
|
||||
// TODO: remove for NativeScript 7.0
|
||||
export function getter<T>(_this: any, property: T | { (): T }): T {
|
||||
@ -54,60 +136,6 @@ export namespace iOSNativeHelper {
|
||||
}
|
||||
}
|
||||
|
||||
export function dataDeserialize(nativeData?: any) {
|
||||
if (isNullOrUndefined(nativeData)) {
|
||||
// some native values will already be js null values
|
||||
// calling types.getClass below on null/undefined will cause crash
|
||||
return null;
|
||||
} else {
|
||||
switch (getClass(nativeData)) {
|
||||
case 'NSNull':
|
||||
return null;
|
||||
case 'NSMutableDictionary':
|
||||
case 'NSDictionary':
|
||||
let obj = {};
|
||||
const length = nativeData.count;
|
||||
const keysArray = nativeData.allKeys as NSArray<any>;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const nativeKey = keysArray.objectAtIndex(i);
|
||||
obj[nativeKey] = dataDeserialize(nativeData.objectForKey(nativeKey));
|
||||
}
|
||||
return obj;
|
||||
case 'NSMutableArray':
|
||||
case 'NSArray':
|
||||
let array = [];
|
||||
const len = nativeData.count;
|
||||
for (let i = 0; i < len; i++) {
|
||||
array[i] = dataDeserialize(nativeData.objectAtIndex(i));
|
||||
}
|
||||
return array;
|
||||
default:
|
||||
return nativeData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function dataSerialize(data?: any) {
|
||||
switch (typeof data) {
|
||||
case 'number':
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
return data;
|
||||
case 'object':
|
||||
if (Array.isArray(data)) {
|
||||
return NSArray.arrayWithArray(<any>data.map(dataSerialize));
|
||||
}
|
||||
|
||||
let obj = {};
|
||||
for (let key of Object.keys(data)) {
|
||||
obj[key] = dataSerialize(data[key]);
|
||||
}
|
||||
return NSDictionary.dictionaryWithDictionary(<any>obj);
|
||||
default:
|
||||
return NSNull.new();
|
||||
}
|
||||
}
|
||||
|
||||
export function isLandscape(): boolean {
|
||||
console.log('utils.ios.isLandscape() is deprecated; use application.orientation instead');
|
||||
|
||||
|
12
packages/core/utils/types.d.ts
vendored
12
packages/core/utils/types.d.ts
vendored
@ -61,6 +61,18 @@ export function isNullOrUndefined(value: any): boolean;
|
||||
*/
|
||||
export function verifyCallback(value: any): void;
|
||||
|
||||
/**
|
||||
* Checks if the number has decimals
|
||||
* @param value Number to check
|
||||
*/
|
||||
export function numberHasDecimals(value: number): boolean;
|
||||
|
||||
/**
|
||||
* Checks if the number is 64 bit
|
||||
* @param value Number to check
|
||||
*/
|
||||
export function numberIs64Bit(value: number): boolean;
|
||||
|
||||
/**
|
||||
* A function that gets the class name of an object.
|
||||
* @param object The object.
|
||||
|
@ -44,6 +44,14 @@ export function verifyCallback(value: any) {
|
||||
}
|
||||
}
|
||||
|
||||
export function numberHasDecimals(value: number): boolean {
|
||||
return !(value % 1 === 0);
|
||||
}
|
||||
|
||||
export function numberIs64Bit(value: number): boolean {
|
||||
return value < -Math.pow(2, 31) + 1 || value > Math.pow(2, 31) - 1;
|
||||
}
|
||||
|
||||
const classInfosMap = new Map<Function, ClassInfo>();
|
||||
|
||||
// ES3-5 type classes are "function blah()", new ES6+ classes can be "class blah"
|
||||
|
Reference in New Issue
Block a user