nsm 1 жил өмнө
commit
b87bb7edd9

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+android/build
+.idea
+*.iml
+ios/.DS_Store
+ios/CParam.xcodeproj/project.xcworkspace/xcuserdata
+ios/CParam.xcodeproj/xcuserdata
+ios/CParam.xcodeproj/xcuserdata/
+ios/CParam.xcodeproj/project.xcworkspace/
+.DS_Store

+ 1 - 0
README.md

@@ -0,0 +1 @@
+CParam

+ 32 - 0
android/build.gradle

@@ -0,0 +1,32 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 23
+    buildToolsVersion '23.0.3'
+
+    defaultConfig {
+        minSdkVersion 16
+        targetSdkVersion 22
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    compile 'com.facebook.react:react-native:+'
+    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    compile 'com.android.support:appcompat-v7:23.+'
+    testCompile 'junit:junit:4.12'
+}

+ 25 - 0
android/proguard-rules.pro

@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/wd/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 26 - 0
android/src/androidTest/java/com/brilliantaero/cparam_android/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.brilliantaero.cparam_android;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() throws Exception {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getTargetContext();
+
+        assertEquals("com.brilliantaero.cparam_android.test", appContext.getPackageName());
+    }
+}

+ 7 - 0
android/src/main/AndroidManifest.xml

@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+
+    package="com.brilliantaero.cparam_android">
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+</manifest>

+ 128 - 0
android/src/main/java/com/brilliantaero/cparam_android/CParamAndroidModule.java

@@ -0,0 +1,128 @@
+package com.brilliantaero.cparam_android;
+
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Created by wd on 03/08/2017.
+ */
+
+public class CParamAndroidModule extends ReactContextBaseJavaModule {
+
+    private static final  String EventName = "GPS_UPDATE";
+    private static int UpdateInterval = 5; // min
+    private  static long minDistanceChangeForUpdate = 50; // 50 meters
+    private  static long minTimeBWUpdates = 1000 * 60 * UpdateInterval;
+    private Timer timer;
+    private ReactApplicationContext context;
+
+    @Override
+    public String getName() {
+        return "CParamAndroid";
+    }
+
+    @Override
+    public Map<String, Object> getConstants() {
+        final Map<String, Object> constants = new HashMap<>();
+        constants.put("GPSUpdateEventName", EventName);
+        constants.put("webviewUserAgent", getWebViewUserAgent());
+        constants.put("userAgent", getUserAgent());
+        return constants;
+    }
+
+    private void sendEvent(ReactContext reactContext,
+                              String eventName,
+                              @Nullable WritableMap params) {
+        //fix在module没有完全加载时调用引发的崩溃
+        if (reactContext.hasActiveCatalystInstance()){
+            reactContext
+                    .getJSModule(RCTNativeAppEventEmitter.class)
+                    .emit(eventName, params);
+        }
+        Log.d("GPS", "sendEvent: ok.");
+    }
+
+    private WritableMap updateGPS(GPSTracker gpsTracker) {
+        WritableMap gps = Arguments.createMap();
+        gpsTracker.getLocation();
+        if (gpsTracker.canGetLocation) {
+            gps.putDouble("lat", gpsTracker.latitude);
+            gps.putDouble("lng", gpsTracker.longitude);
+        }
+        return gps;
+    }
+
+    public CParamAndroidModule(final ReactApplicationContext reactContext) {
+        super(reactContext);
+        context = reactContext;
+        final GPSTracker gpsTracker = new GPSTracker(reactContext,
+                minDistanceChangeForUpdate,
+                minTimeBWUpdates);
+
+        //开启定时器
+        TimerTask task = new TimerTask() {
+            @Override
+            public void run() {
+                gpsTracker.getLocation();
+                if (gpsTracker.canGetLocation) {
+                    WritableMap gps = Arguments.createMap();
+                    gps.putDouble("lat", gpsTracker.latitude);
+                    gps.putDouble("lng", gpsTracker.longitude);
+                    sendEvent(reactContext, EventName, gps);
+                }
+            }
+        };
+
+        timer = new Timer();
+        timer.schedule(task, 1000, minTimeBWUpdates);
+
+    }
+
+    @ReactMethod
+    public void setNativeCparams(ReadableMap map){
+       HashMap<String,Object> hashMap = map.toHashMap();
+       HashMap<String,String> cParams = new HashMap<>();
+       Iterator<String> iterator = hashMap.keySet().iterator();
+       while (iterator.hasNext()){
+           String key = iterator.next();
+           if (hashMap.get(key) != null) {
+               cParams.put(key,hashMap.get(key).toString());
+           }
+       }
+       CParams.getInstance(context).setCparamsFromJS(cParams);
+    }
+
+    public String getUserAgent(){
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return System.getProperty("http.agent");
+        }
+
+        return "";
+    }
+
+    public String getWebViewUserAgent(){
+        if (Build.VERSION.SDK_INT >= 17) {
+            return WebSettings.getDefaultUserAgent(context);
+        }
+        return new WebView(context).getSettings().getUserAgentString();
+    }
+
+}

+ 33 - 0
android/src/main/java/com/brilliantaero/cparam_android/CParamAndroidPackage.java

@@ -0,0 +1,33 @@
+package com.brilliantaero.cparam_android;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created by wd on 03/08/2017.
+ */
+
+public class CParamAndroidPackage implements ReactPackage {
+
+    @Override
+    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
+        return Arrays.asList(new NativeModule[]{
+                new CParamAndroidModule(reactContext),
+        });
+    }
+    public List<Class<? extends JavaScriptModule>> createJSModules() {
+        return Collections.emptyList();
+    }
+    @Override
+    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
+        return Collections.emptyList();
+    }
+
+}

+ 249 - 0
android/src/main/java/com/brilliantaero/cparam_android/CParams.java

@@ -0,0 +1,249 @@
+package com.brilliantaero.cparam_android;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.Bundle;
+import android.telephony.TelephonyManager;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.UUID;
+
+import static android.os.Build.UNKNOWN;
+
+/**
+ * Created by wd on 08/08/2017.
+ */
+
+public class CParams {
+    private Context mActivity;
+    private Bundle bundle;
+
+    private final String CID_KEY = "BUGLY_APP_CHANNEL";
+    private final String PID_KEY = "com.brilliantaero.pid";
+    private final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
+
+    private HashMap<String,String> cparamsFromJS = null;
+
+    private CParams(Context activity) {
+        mActivity = activity;
+
+        try {
+            bundle = mActivity.getPackageManager().getApplicationInfo(activity.getPackageName(), PackageManager.GET_META_DATA).metaData;
+        }catch(Exception e) {}
+
+    }
+
+    public HashMap<String, String> getInitParams() {
+        String channel = getCid();
+        return getInitParams(channel);
+    }
+
+    public HashMap<String, String> getInitParams(String channel) {
+        HashMap<String, String> initPrams = new HashMap<>();
+        initPrams.put("vid", getVid());
+        initPrams.put("cid", channel);
+        initPrams.put("pid", getPid());
+        initPrams.put("gid", getGid());
+        initPrams.put("uid", getUid());
+        initPrams.put("model", getModel());
+        initPrams.put("osVersion", getOsVersion());
+        initPrams.put("mno", getMno());
+        initPrams.put("env", getEnv());
+        initPrams.put("iccid",getIccid());
+        initPrams.put("serial", getDeviceSerial());
+        return initPrams;
+    }
+
+    public String getDeviceSerial() {
+        try {
+            Class<?> c = Class.forName("android.os.SystemProperties");
+            Method get = c.getMethod("get", String.class, String.class);
+            String serial = (String)get.invoke(c, "ro.lenovosn2", UNKNOWN);
+            if (serial.equals(UNKNOWN))
+                return null;
+            return serial;
+        } catch (Exception ignored) {
+            ignored.printStackTrace();
+            return "";
+        }
+    }
+
+    public String getIccid() {
+        try {
+            TelephonyManager manager = (TelephonyManager) mActivity.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
+            if (manager.getSimSerialNumber() == null)
+                return null;
+            return manager.getSimSerialNumber();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return UNKNOWN;
+        }
+    }
+
+    public Object getBuildConfigValue(String fieldName) {
+        Context context = mActivity.getApplicationContext();
+        try {
+            int resId = context.getResources().getIdentifier("build_config_package", "string", context.getPackageName());
+            String className;
+            try {
+                className = context.getString(resId);
+            } catch (Resources.NotFoundException e) {
+                className = context.getPackageName();
+            }
+            Class clazz = Class.forName(className + ".BuildConfig");
+            Field field = clazz.getField(fieldName);
+            return field.get(clazz);
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        } catch (NoSuchFieldException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public String getVid() {
+        // vid 版本信息
+
+        String version_name = getBuildConfigValue("VERSION_NAME").toString();
+        String version_code = getBuildConfigValue("VERSION_CODE").toString();
+        if(version_code ==null)
+            version_code = "";
+
+        if(version_name == null)
+            version_name = "";
+
+        return version_name + "-" + version_code;
+        // return BuildConfig.VERSION_NAME + "." + BuildConfig.VERSION_CODE;
+    }
+
+    public String getCid() {
+        //cid: "C1001", 渠道号,如C1001为appStore, C1002为iPhone越狱渠道, 不同的渠道打不同的包
+        // iPhone C1001, Android 是 C2001
+        String cid = "";
+        try {
+            cid = bundle.getString(CID_KEY);
+        } catch (Exception e) {}
+        return cid;
+    }
+
+    public String getPid() {
+        // pid: "10010", 程序号:区分pro、免费版本
+        // iPhone 是 P1001, Android 是 P2001
+        String pid = "";
+        try {
+            pid = bundle.getString(PID_KEY);
+        } catch (Exception e) {}
+        return pid;
+    }
+
+    public String getGid() {
+        //gid: "", 客户端的Gid
+        return "";
+    }
+
+    public String getUid () {
+        //uid:"", UUID, android 为手机串号,ios7以后为apple广告id
+        String deviceId;
+        SharedPreferences sharedPreferences = mActivity.getSharedPreferences(PREF_UNIQUE_ID, mActivity.MODE_PRIVATE);
+        deviceId = sharedPreferences.getString(PREF_UNIQUE_ID, null);
+        if(deviceId == null) {
+            try {
+                final TelephonyManager tm = (TelephonyManager) mActivity.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
+
+                final String tmDevice, tmSerial, androidId;
+                tmDevice = "" + tm.getDeviceId();
+                tmSerial = "" + tm.getSimSerialNumber();
+                androidId = "" + android.provider.Settings.Secure.getString(mActivity.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
+
+                UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
+                deviceId = deviceUuid.toString();
+            } catch (Exception e){
+                e.printStackTrace();
+                deviceId = UUID.randomUUID().toString();
+            }
+            SharedPreferences.Editor editor = sharedPreferences.edit();
+            editor.putString(PREF_UNIQUE_ID, deviceId);
+            editor.commit();
+        }
+
+        return deviceId;
+    }
+
+    public String getModel() {
+        //model: "", iPhone型号
+        return getDeviceName();
+    }
+
+    public String getOsVersion() {
+        //osVersion: "", 系统版本
+        return Build.VERSION.RELEASE;
+    }
+
+    public String getMno() {
+        //mno: "", 用户所在的运营商
+        TelephonyManager manager = (TelephonyManager) mActivity.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
+        String carrierName = manager.getNetworkOperatorName();
+        if (carrierName.equals(""))
+            return null;
+        return carrierName;
+    }
+
+    public String getEnv() {
+        String env = getBuildConfigValue("ENV").toString();
+        return env;
+    }
+
+    public String getDeviceName() {
+        String manufacturer = Build.MANUFACTURER;
+        String model = Build.MODEL;
+        if (model.startsWith(manufacturer)) {
+            return capitalize(model);
+        } else {
+            return capitalize(manufacturer) + " " + model;
+        }
+    }
+
+    public String capitalize(String s) {
+        if (s == null || s.length() == 0) {
+            return "";
+        }
+        char first = s.charAt(0);
+        if (Character.isUpperCase(first)) {
+            return s;
+        } else {
+            return Character.toUpperCase(first) + s.substring(1);
+        }
+    }
+
+    public void setCparamsFromJS(HashMap<String,String> params){
+        cparamsFromJS = params;
+    }
+
+    public HashMap<String, String> getCparamsFromJS(){
+        if (cparamsFromJS == null)
+            return getInitParams();
+        return cparamsFromJS;
+    }
+
+    public static class CParamsHolder{
+        private static CParams cParams = null;
+
+        public static void newCparams(Context context){
+            cParams = new CParams(context);
+        }
+    }
+
+    public static CParams getInstance(Context context){
+        if (CParamsHolder.cParams == null){
+            CParamsHolder.newCparams(context);
+        }
+        return CParamsHolder.cParams;
+    }
+
+}

+ 192 - 0
android/src/main/java/com/brilliantaero/cparam_android/GPSTracker.java

@@ -0,0 +1,192 @@
+package com.brilliantaero.cparam_android;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.util.Log;
+
+/**
+ * Created by wd on 04/08/2017.
+ * From: https://stackoverflow.com/questions/1513485/how-do-i-get-the-current-gps-location-programmatically-in-android
+ */
+
+
+public class GPSTracker extends Service implements LocationListener {
+
+    private final Context mContext;
+    private final long minDistanceChangeForUpdate;
+    private final long minTimeBWUpdates;
+
+    // Flag for GPS status
+    boolean isGPSEnabled = false;
+
+    // Flag for network status
+    boolean isNetworkEnabled = false;
+
+    // Flag for GPS status
+    boolean canGetLocation = false;
+
+    Location location; // Location
+    double latitude; // Latitude
+    double longitude; // Longitude
+
+    // The minimum distance to change Updates in meters
+    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
+
+    // The minimum time between updates in milliseconds
+    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute
+
+    // Declaring a Location Manager
+    protected LocationManager locationManager;
+
+
+    public GPSTracker(Context context) {
+        this.mContext = context;
+        this.minDistanceChangeForUpdate = MIN_DISTANCE_CHANGE_FOR_UPDATES;
+        this.minTimeBWUpdates = MIN_TIME_BW_UPDATES;
+    }
+
+    public GPSTracker(Context context,
+                      long minDistanceChangeForUpdate,
+                      long minTimeBWUpdates) {
+        this.mContext = context;
+        this.minDistanceChangeForUpdate = minDistanceChangeForUpdate;
+        this.minTimeBWUpdates = minTimeBWUpdates;
+    }
+
+    public Location getLocation() {
+        try {
+            locationManager = (LocationManager) mContext
+                    .getSystemService(LOCATION_SERVICE);
+
+            // Getting GPS status
+            isGPSEnabled = locationManager
+                    .isProviderEnabled(LocationManager.GPS_PROVIDER);
+
+            // Getting network status
+            isNetworkEnabled = locationManager
+                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+
+            if (!isGPSEnabled && !isNetworkEnabled) {
+                Log.d("GPS", "GPS disabled.");
+                // No network provider is enabled
+            } else {
+                this.canGetLocation = true;
+                if (isNetworkEnabled) {
+                    locationManager.requestLocationUpdates(
+                            LocationManager.NETWORK_PROVIDER,
+                            this.minTimeBWUpdates,
+                            this.minDistanceChangeForUpdate, this, Looper.getMainLooper());
+                    Log.d("GPS", "Network enabled.");
+                    if (locationManager != null) {
+                        location = locationManager
+                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+                        if (location != null) {
+                            latitude = location.getLatitude();
+                            longitude = location.getLongitude();
+                        }
+                    }
+                }
+                // If GPS enabled, get latitude/longitude using GPS Services
+                if (isGPSEnabled) {
+                    if (location == null) {
+                        locationManager.requestLocationUpdates(
+                                LocationManager.GPS_PROVIDER,
+                                this.minTimeBWUpdates,
+                                this.minDistanceChangeForUpdate, this, Looper.getMainLooper());
+                        Log.d("GPS", "GPS Enabled");
+                        if (locationManager != null) {
+                            location = locationManager
+                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
+                            if (location != null) {
+                                latitude = location.getLatitude();
+                                longitude = location.getLongitude();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return location;
+    }
+
+
+    /**
+     * Stop using GPS listener
+     * Calling this function will stop using GPS in your app.
+     * */
+    public void stopUsingGPS(){
+        if(locationManager != null){
+            locationManager.removeUpdates(GPSTracker.this);
+        }
+    }
+
+
+    /**
+     * Function to get latitude
+     * */
+    public double getLatitude(){
+        if(location != null){
+            latitude = location.getLatitude();
+        }
+
+        // return latitude
+        return latitude;
+    }
+
+
+    /**
+     * Function to get longitude
+     * */
+    public double getLongitude(){
+        if(location != null){
+            longitude = location.getLongitude();
+        }
+
+        // return longitude
+        return longitude;
+    }
+
+    /**
+     * Function to check GPS/Wi-Fi enabled
+     * @return boolean
+     * */
+    public boolean canGetLocation() {
+        return this.canGetLocation;
+    }
+
+    @Override
+    public void onLocationChanged(Location location) {
+    }
+
+
+    @Override
+    public void onProviderDisabled(String provider) {
+    }
+
+
+    @Override
+    public void onProviderEnabled(String provider) {
+    }
+
+
+    @Override
+    public void onStatusChanged(String provider, int status, Bundle extras) {
+    }
+
+
+    @Override
+    public IBinder onBind(Intent arg0) {
+        return null;
+    }
+}

+ 2 - 0
android/src/main/res/values/strings.xml

@@ -0,0 +1,2 @@
+<resources>
+</resources>

+ 17 - 0
android/src/test/java/com/brilliantaero/cparam_android/ExampleUnitTest.java

@@ -0,0 +1,17 @@
+package com.brilliantaero.cparam_android;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() throws Exception {
+        assertEquals(4, 2 + 2);
+    }
+}

+ 26 - 0
index.js

@@ -0,0 +1,26 @@
+'use strict';
+
+import React, { NativeModules, Platform } from 'react-native';
+
+let RCTCParamAndroid = NativeModules.CParamAndroid;
+let RCTCParamIOS = NativeModules.CParam;
+let RCTCParam;
+
+if (Platform.OS === 'ios') {
+    RCTCParam = RCTCParamIOS;
+} else {
+    RCTCParam = RCTCParamAndroid;
+}
+
+export class CParamModule{
+    static setNativeCparams(cparams){
+        if(RCTCParam.setNativeCparams != undefined){
+            RCTCParam.setNativeCparams(cparams);
+        }
+    }
+
+    static webviewUserAgent = RCTCParam.webviewUserAgent;
+    static userAgent = RCTCParam.userAgent;
+}
+
+export default RCTCParam;

+ 321 - 0
ios/CParam.xcodeproj/project.pbxproj

@@ -0,0 +1,321 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		85C72B551F38414D00710D52 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 85C72B541F38414D00710D52 /* CoreLocation.framework */; };
+		85C72B7E1F384E6B00710D52 /* LocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 85C72B7D1F384E6B00710D52 /* LocationManager.m */; };
+		A8FABBC41EF9236700C839BD /* CParam.m in Sources */ = {isa = PBXBuildFile; fileRef = A8FABBC31EF9236700C839BD /* CParam.m */; };
+		A8FABBC51EF9236700C839BD /* CParam.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = A8FABBC21EF9236700C839BD /* CParam.h */; };
+		A8FABBCD1EF924FC00C839BD /* DataController.m in Sources */ = {isa = PBXBuildFile; fileRef = A8FABBCC1EF924FC00C839BD /* DataController.m */; };
+		A8FABBD01EF925AA00C839BD /* IdentityData.m in Sources */ = {isa = PBXBuildFile; fileRef = A8FABBCF1EF925AA00C839BD /* IdentityData.m */; };
+		A8FABBD41EF9280F00C839BD /* SSKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = A8FABBD31EF9280F00C839BD /* SSKeychain.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		A8FABBBD1EF9236700C839BD /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "include/$(PRODUCT_NAME)";
+			dstSubfolderSpec = 16;
+			files = (
+				A8FABBC51EF9236700C839BD /* CParam.h in CopyFiles */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		85C72B541F38414D00710D52 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
+		85C72B7C1F384E6B00710D52 /* LocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocationManager.h; sourceTree = "<group>"; };
+		85C72B7D1F384E6B00710D52 /* LocationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocationManager.m; sourceTree = "<group>"; };
+		A8FABBBF1EF9236700C839BD /* libCParam.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCParam.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		A8FABBC21EF9236700C839BD /* CParam.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParam.h; sourceTree = "<group>"; };
+		A8FABBC31EF9236700C839BD /* CParam.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CParam.m; sourceTree = "<group>"; };
+		A8FABBCB1EF924FC00C839BD /* DataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataController.h; sourceTree = "<group>"; };
+		A8FABBCC1EF924FC00C839BD /* DataController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataController.m; sourceTree = "<group>"; };
+		A8FABBCE1EF925AA00C839BD /* IdentityData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdentityData.h; sourceTree = "<group>"; };
+		A8FABBCF1EF925AA00C839BD /* IdentityData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdentityData.m; sourceTree = "<group>"; };
+		A8FABBD21EF9280F00C839BD /* SSKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKeychain.h; sourceTree = "<group>"; };
+		A8FABBD31EF9280F00C839BD /* SSKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKeychain.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		A8FABBBC1EF9236700C839BD /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				85C72B551F38414D00710D52 /* CoreLocation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		85C72B531F38414D00710D52 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				85C72B541F38414D00710D52 /* CoreLocation.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		A8FABBB61EF9236700C839BD = {
+			isa = PBXGroup;
+			children = (
+				A8FABBC11EF9236700C839BD /* CParam */,
+				A8FABBC01EF9236700C839BD /* Products */,
+				85C72B531F38414D00710D52 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		A8FABBC01EF9236700C839BD /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				A8FABBBF1EF9236700C839BD /* libCParam.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		A8FABBC11EF9236700C839BD /* CParam */ = {
+			isa = PBXGroup;
+			children = (
+				A8FABBD11EF9280F00C839BD /* SSKeychain */,
+				A8FABBC21EF9236700C839BD /* CParam.h */,
+				A8FABBC31EF9236700C839BD /* CParam.m */,
+				A8FABBCB1EF924FC00C839BD /* DataController.h */,
+				A8FABBCC1EF924FC00C839BD /* DataController.m */,
+				A8FABBCE1EF925AA00C839BD /* IdentityData.h */,
+				A8FABBCF1EF925AA00C839BD /* IdentityData.m */,
+				85C72B7C1F384E6B00710D52 /* LocationManager.h */,
+				85C72B7D1F384E6B00710D52 /* LocationManager.m */,
+			);
+			path = CParam;
+			sourceTree = "<group>";
+		};
+		A8FABBD11EF9280F00C839BD /* SSKeychain */ = {
+			isa = PBXGroup;
+			children = (
+				A8FABBD21EF9280F00C839BD /* SSKeychain.h */,
+				A8FABBD31EF9280F00C839BD /* SSKeychain.m */,
+			);
+			path = SSKeychain;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		A8FABBBE1EF9236700C839BD /* CParam */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = A8FABBC81EF9236700C839BD /* Build configuration list for PBXNativeTarget "CParam" */;
+			buildPhases = (
+				A8FABBBB1EF9236700C839BD /* Sources */,
+				A8FABBBC1EF9236700C839BD /* Frameworks */,
+				A8FABBBD1EF9236700C839BD /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = CParam;
+			productName = CParam;
+			productReference = A8FABBBF1EF9236700C839BD /* libCParam.a */;
+			productType = "com.apple.product-type.library.static";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		A8FABBB71EF9236700C839BD /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0900;
+				ORGANIZATIONNAME = Breeze;
+				TargetAttributes = {
+					A8FABBBE1EF9236700C839BD = {
+						CreatedOnToolsVersion = 8.3.3;
+						ProvisioningStyle = Automatic;
+					};
+				};
+			};
+			buildConfigurationList = A8FABBBA1EF9236700C839BD /* Build configuration list for PBXProject "CParam" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = A8FABBB61EF9236700C839BD;
+			productRefGroup = A8FABBC01EF9236700C839BD /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				A8FABBBE1EF9236700C839BD /* CParam */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		A8FABBBB1EF9236700C839BD /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				85C72B7E1F384E6B00710D52 /* LocationManager.m in Sources */,
+				A8FABBD01EF925AA00C839BD /* IdentityData.m in Sources */,
+				A8FABBD41EF9280F00C839BD /* SSKeychain.m in Sources */,
+				A8FABBC41EF9236700C839BD /* CParam.m in Sources */,
+				A8FABBCD1EF924FC00C839BD /* DataController.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		A8FABBC61EF9236700C839BD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+			};
+			name = Debug;
+		};
+		A8FABBC71EF9236700C839BD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		A8FABBC91EF9236700C839BD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+			};
+			name = Debug;
+		};
+		A8FABBCA1EF9236700C839BD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				OTHER_LDFLAGS = "-ObjC";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		A8FABBBA1EF9236700C839BD /* Build configuration list for PBXProject "CParam" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				A8FABBC61EF9236700C839BD /* Debug */,
+				A8FABBC71EF9236700C839BD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		A8FABBC81EF9236700C839BD /* Build configuration list for PBXNativeTarget "CParam" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				A8FABBC91EF9236700C839BD /* Debug */,
+				A8FABBCA1EF9236700C839BD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = A8FABBB71EF9236700C839BD /* Project object */;
+}

+ 19 - 0
ios/CParam/CParam.h

@@ -0,0 +1,19 @@
+//
+//  CParam.h
+//  CParam
+//
+//  Created by breeze on 2017/6/20.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <React/RCTBridgeModule.h>
+#import <React/RCTEventEmitter.h>
+
+@interface CParam : RCTEventEmitter <RCTBridgeModule>
+
++ (instancetype) shareInstance;
+
+- (NSDictionary *)cparams;
+
+@end

+ 142 - 0
ios/CParam/CParam.m

@@ -0,0 +1,142 @@
+//
+//  CParam.m
+//  CParam
+//
+//  Created by breeze on 2017/6/20.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import "CParam.h"
+#import <React/RCTBridge.h>
+#import <React/RCTEventDispatcher.h>
+#import "DataController.h"
+#import "LocationManager.h"
+#import <Foundation/NSTimer.h>
+
+static CParam *_instance;
+
+@interface CParam () <LocationManagerDelegate>
+
+@property (nonatomic) bool hasListeners;
+
+@property (nonatomic, strong) NSString *eventName;
+
+@property (nonatomic, strong) NSTimer *timer;
+
+@property (nonatomic, strong) NSDictionary *cparams;
+
+@end
+
+@implementation CParam
+
+RCT_EXPORT_MODULE();
+
++(instancetype)allocWithZone:(struct _NSZone *)zone
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        if (_instance == nil) {
+            _instance = [super allocWithZone:zone];
+        }
+    });
+    return _instance;
+}
+
++(instancetype)shareInstance {
+    return [[self alloc] init];
+}
+// 为了严谨,也要重写copyWithZone 和 mutableCopyWithZone
+-(id)copyWithZone:(NSZone *)zone {
+    return _instance;
+}
+-(id)mutableCopyWithZone:(NSZone *)zone {
+    return _instance;
+}
+
+
+- (void)dealloc {
+    if (_timer.valid) {
+        [_timer invalidate];
+    }
+}
+
++ (BOOL)requiresMainQueueSetup {
+    return YES;
+}
+
+- (instancetype)init {
+    if (self = [super init]) {
+//        [LocationManager shareInstance].delegate = self;
+//
+//        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+//            [[LocationManager shareInstance] startUpdatingLocation];
+//        });
+//
+//        self.timer = [NSTimer scheduledTimerWithTimeInterval: 300
+//                                                      target: self
+//                                                    selector: @selector(timeout)
+//                                                    userInfo: nil
+//                                                     repeats: YES];
+    }
+    
+    return self;
+}
+
+- (void)timeout {
+    [[LocationManager shareInstance] startUpdatingLocation];
+}
+
+- (NSString *)eventName {
+    return @"GPS_UPDATE";
+}
+
+- (NSArray<NSString *> *)supportedEvents {
+    return @[self.eventName];
+}
+
+- (NSDictionary<NSString *, id> *)constantsToExport {
+    return @{@"GPSUpdateEventName": self.eventName};
+}
+
+// 在添加第一个监听函数时触发
+-(void)startObserving {
+    self.hasListeners = YES;
+    // Set up any upstream listeners or background tasks as necessary
+}
+
+// Will be called when this module's last listener is removed, or on dealloc.
+-(void)stopObserving {
+    self.hasListeners = NO;
+    // Remove upstream listeners, stop unnecessary background tasks
+}
+
+
+- (void)updateLocationWithCoordinate:(CLLocationCoordinate2D)coordinate {
+    
+    if (self.hasListeners) { // Only send events if anyone is listening
+        NSNumber *latitude = [NSNumber numberWithFloat:coordinate.latitude];
+        NSNumber *longitude = [NSNumber numberWithFloat:coordinate.longitude];
+        [self sendEventWithName: self.eventName body:@{@"lat": latitude, @"lng": longitude}];
+    }
+}
+
+
+RCT_EXPORT_METHOD(setNativeCparams: (nonnull NSDictionary *)cparams) {
+    
+    NSMutableDictionary *resDict = [[NSMutableDictionary alloc] init];
+    for (NSString *key in cparams) {
+        id val = cparams[key];
+        if (val) {
+            [resDict setValue: val forKey: key];
+        }
+    }
+    
+    _cparams = [resDict copy];
+}
+
+- (NSDictionary *)cparams {
+    return _cparams;
+}
+
+
+@end

+ 75 - 0
ios/CParam/DataController.h

@@ -0,0 +1,75 @@
+//
+//  DataController.h
+//  CParam
+//
+//  Created by breeze on 2017/6/20.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface DataController : NSObject
+
+// 获取数据管理的控制器(单例,防止全局变量的使用)
++ (DataController *)getInstance;
+
+// ===================================================================
+// 获取和设置ID
+// ===================================================================
+// GID
+- (NSString *)appGID;
+- (void)setAppGID:(NSString *)appGIDNew;
+
+// UID
+- (NSString *)appUID;
+- (void)setAppUID:(NSString *)appUIDNew;
+
+// 获取程序ServerID
+- (NSString *)serverID;
+- (void)setServerID:(NSString *)serverIDNew;
+
+// 获取UID
+- (NSString *)vendorUID;
+
+// 获取Apple ID
+- (NSString *)deviceUID;
+
+
+// 获取Mac地址
++ (NSString *)macAddress;
+
+// 获取iPhone型号
++ (NSString *)platform;
+
+// 系统型号
++ (NSString *)osVersion;
+
+// 获取App的版本号,包含buildID, 如:1.0.0-3 其中1.0.0为appVersion,3位build ID
++ (NSString *)appVersion;
+
+// 获取build号
++ (NSString *)appBuildID;
+
+// 具体设备型号
++ (NSString *)deviceModelName;
+
++ (NSString *)bundleID;
+
+// ===================================================================
+// 保存
+// ===================================================================
+// 保存GID
+- (void)saveAppGID;
+
+// 保存UID
+- (void)saveAppUID;
+
+// 保存ServerID
+- (void)saveServerID;
+
+// 保存UID
+- (void)saveDeviceUID;
+
++ (id)getCarrierCode;
+
+@end

+ 636 - 0
ios/CParam/DataController.m

@@ -0,0 +1,636 @@
+//
+//  DataController.m
+//  CParam
+//
+//  Created by breeze on 2017/6/20.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import "DataController.h"
+#import "IdentityData.h"
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#import "SSKeychain.h"
+#import <UIKit/UIKit.h>
+#import <sys/utsname.h>
+#import <CoreTelephony/CTCarrier.h>
+#import <CoreTelephony/CTTelephonyNetworkInfo.h>
+
+
+#define kAppGIDFile									@"appGID.dat"
+#define kServerIDFile								@"appSID.dat"
+#define kDeviceUIDFile                              @"deviceUID.dat"
+#define kAppUIDFile                                 @"appUID.dat"
+
+// 全局数据控制器
+static DataController *globalDataController = nil;
+
+@implementation DataController
+{
+    IdentityData *identityData;		// 身份数据
+}
+
+
+// 获取数据管理的控制器
++ (DataController *)getInstance
+{
+    @synchronized(self)
+    {
+        // 实例对象只分配一次
+        if(globalDataController == nil)
+        {
+            globalDataController = [[super allocWithZone:NULL] init];
+        }
+    }
+    
+    return globalDataController;
+}
+
++ (id)allocWithZone:(NSZone *)zone
+{
+    return [self getInstance];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    return self;
+}
+
+
+// 初始化
+- (void)initIdentityData
+{
+    if(identityData == nil)
+    {
+        identityData = [[IdentityData alloc] init];
+    }
+}
+
++ (NSString*)getAppGroupID
+{
+    //获取Bundle identifier
+    NSDictionary *dic = [[NSBundle mainBundle] infoDictionary];
+    NSString *appName = [dic objectForKey:@"CFBundleIdentifier"];
+    
+    // 查找第一个点
+    NSRange range = [appName rangeOfString:@"."];
+    // 取第一个点及后面的内容
+    NSString* subString = [appName substringWithRange:NSMakeRange(range.location, [appName length]-range.location)];
+    
+    // 连接字符串
+    NSString* appGroupName = [@"group" stringByAppendingString:subString];
+    return appGroupName;
+}
+
+#pragma mark - 获取和设置程序用户ID
+// ===================================================================
+// 获取和设置程序用户ID
+// ===================================================================
+// 获取程序用户ID
+- (NSString *)appGID
+{
+    [self initIdentityData];
+    
+    // 如果没有加载
+    if([identityData appGID] == nil)
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 加载GID文件
+        NSString *appGIDPath = [documentDirectory stringByAppendingPathComponent: kAppGIDFile];
+        
+        // 该文件存在
+        if([[NSFileManager defaultManager] fileExistsAtPath:appGIDPath])
+        {
+            NSString *appIDFromFile = [[NSString alloc] initWithContentsOfFile:appGIDPath
+                                                                      encoding:NSUTF8StringEncoding
+                                                                         error:nil];
+            [self setAppGID:appIDFromFile];
+        }
+        // 该文件不存在,设置成默认值(空字符串)
+        else
+        {
+            [self setAppGID:@""];
+        }
+    }
+    
+    return [identityData appGID];
+}
+
+// 设置程序用户ID
+- (void)setAppGID:(NSString *)appGIDNew
+{
+    [self initIdentityData];
+    [identityData setAppGID:appGIDNew];
+}
+
+// 获取程序用户UID
+- (NSString *)appUID
+{
+    [self initIdentityData];
+    
+    // 如果没有加载
+    if([identityData appUID] == nil)
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 加载UID文件
+        NSString *appUIDPath = [documentDirectory stringByAppendingPathComponent:kAppUIDFile];
+        
+        //获取sandbox的UID
+        NSString *appIDFromFile = [[NSString alloc] initWithContentsOfFile:appUIDPath
+                                                                  encoding:NSUTF8StringEncoding
+                                                                     error:nil];
+        //获取keychain的UID
+        NSString *appIDFromKeychain = [SSKeychain passwordForService:@"com.brilliantAreo.userClient"account:@"iid"];
+        
+        NSString *uuidStr = nil;
+        BOOL shouldSaveSandBox = NO;
+        BOOL shouldSaveKeychain = NO;
+        
+        //同时存在
+        if ((appIDFromFile.length > 0) && (appIDFromKeychain.length > 0))
+        {
+            uuidStr = appIDFromFile;
+            if (![appIDFromFile isEqualToString:appIDFromKeychain])
+            {
+                shouldSaveKeychain = YES;
+            }
+        }
+        //沙盒不存在,Keychain存在
+        else if ((appIDFromFile.length == 0) && (appIDFromKeychain.length > 0))
+        {
+            uuidStr = appIDFromKeychain;
+            shouldSaveSandBox = YES;
+        }
+        //沙盒存在,Keychain不存在
+        else if ((appIDFromFile.length > 0) && (appIDFromKeychain.length == 0))
+        {
+            uuidStr = appIDFromFile;
+            shouldSaveKeychain = YES;
+        }
+        //同时不存在
+        else
+        {
+            if([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)])
+            {
+                uuidStr = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
+                shouldSaveKeychain = YES;
+                shouldSaveSandBox = YES;
+            }
+        }
+        
+        [self setAppUID:uuidStr];//设置APPUID
+        
+        if (shouldSaveSandBox)
+        {
+            [self saveAppUID];//保存沙盒
+        }
+        if (shouldSaveKeychain)
+        {
+            [SSKeychain setPassword:uuidStr
+                         forService:@"com.brilliantAreo.userClient" account:@"iid"];//保存Keychain
+        }
+    }
+    
+    return [identityData appUID];
+}
+
+// 设置程序用户UID
+- (void)setAppUID:(NSString *)appUIDNew
+{
+    [self initIdentityData];
+    [identityData setAppUID:appUIDNew];
+}
+
+#pragma mark - 获取服务端分配的ServerID
+// ===================================================================
+// 获取和设置程序用户ID
+// ===================================================================
+// 获取程序ServerID
+- (NSString *)serverID
+{
+    [self initIdentityData];
+    
+    // 如果没有加载
+    if([identityData serverID] == nil)
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 加载ServerID文件
+        NSString *serverIDPath = [documentDirectory stringByAppendingPathComponent:kServerIDFile];
+        
+        // 该文件存在
+        if([[NSFileManager defaultManager] fileExistsAtPath:serverIDPath])
+        {
+            NSString *serverIDFromFile = [[NSString alloc] initWithContentsOfFile:serverIDPath
+                                                                         encoding:NSUTF8StringEncoding
+                                                                            error:nil];
+            [self setServerID:serverIDFromFile];
+        }
+        // 该文件不存在,设置成默认值(空字符串)
+        else
+        {
+            [self setServerID:@""];
+        }
+    }
+    
+    return [identityData serverID];
+}
+
+// 设置程序用户ID
+- (void)setServerID:(NSString *)serverIDNew
+{
+    [self initIdentityData];
+    [identityData setServerID:serverIDNew];
+}
+
+#pragma mark - 获取和设置deviceUID
+// 获取UID
+- (NSString *)deviceUID
+{
+    [self initIdentityData];
+    
+    // 如果没有加载
+    if([identityData deviceUID] == nil)
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 加载UID文件
+        NSString *deviceUIDPath = [documentDirectory stringByAppendingPathComponent:kDeviceUIDFile];
+        
+        // 该文件存在
+        if([[NSFileManager defaultManager] fileExistsAtPath:deviceUIDPath])
+        {
+            NSString *deviceUIDFromFile = [[NSString alloc] initWithContentsOfFile:deviceUIDPath
+                                                                          encoding:NSUTF8StringEncoding
+                                                                             error:nil];
+            [self setDeviceUID:deviceUIDFromFile];
+        }
+        // 该文件不存在,则通过方式获取该唯一标识
+        else
+        {
+            // 产生唯一标识
+            CFUUIDRef puuid = CFUUIDCreate(nil);
+            CFStringRef uuidString = CFUUIDCreateString(nil, puuid);
+            NSString * deviceID = (__bridge_transfer  NSString *)CFStringCreateCopy(NULL, uuidString);
+            CFRelease(puuid);
+            CFRelease(uuidString);
+            
+            [self setDeviceUID:deviceID];
+            
+            // 保存到文件中
+            [self saveDeviceUID];
+        }
+    }
+    
+    return [identityData deviceUID];
+}
+
+// 设置UID
+- (void)setDeviceUID:(NSString *)deviceUIDNew
+{
+    [self initIdentityData];
+    [identityData setDeviceUID:deviceUIDNew];
+}
+
+// 获取Mac地址
+// Return the local MAC addy
+// Courtesy of FreeBSD hackers email list
+// Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb.
++ (NSString *)macAddress
+{
+    int                 mib[6];
+    size_t              len;
+    char                *buf;
+    unsigned char       *ptr;
+    struct if_msghdr    *ifm;
+    struct sockaddr_dl  *sdl;
+    
+    mib[0] = CTL_NET;
+    mib[1] = AF_ROUTE;
+    mib[2] = 0;
+    mib[3] = AF_LINK;
+    mib[4] = NET_RT_IFLIST;
+    
+    if ((mib[5] = if_nametoindex("en0")) == 0)
+    {
+        return @"";
+    }
+    
+    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+    {
+        return @"";
+    }
+    
+    if ((buf = malloc(len)) == NULL)
+    {
+        return @"";
+    }
+    
+    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
+    {
+        free(buf);
+        return @"";
+    }
+    
+    ifm = (struct if_msghdr *)buf;
+    sdl = (struct sockaddr_dl *)(ifm + 1);
+    ptr = (unsigned char *)LLADDR(sdl);
+    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
+                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
+    free(buf);
+    
+    return outstring;
+}
+
+// 获取platform
++ (NSString *)platform
+{
+    size_t size;
+    
+    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+    
+    char *machine = malloc(size);
+    
+    sysctlbyname("hw.machine", machine, &size, NULL, 0);
+    
+    NSString *platform = [NSString stringWithCString:machine
+                                            encoding:NSUTF8StringEncoding];
+    
+    free(machine);
+    
+    return platform;
+}
+
+- (NSString *)vendorUID
+{
+    // UID
+#if TARGET_IPHONE_SIMULATOR
+    NSString *deviceID = @"0000000000000000000000000000000000000000";
+#elif TARGET_OS_IPHONE
+    NSString *deviceID = [DataController macAddress];
+    
+    if ([deviceID isEqualToString:@"02:00:00:00:00:00"] || (deviceID == nil))
+    {
+        return [self appUID];
+    }
+#endif
+    
+    return deviceID;
+}
+
+#pragma mark - 保存
+// ===================================================================
+// 程序用户ID存储函数
+// ===================================================================
+// 保存AppID
+- (void)saveAppGID
+{
+    if((identityData != nil) && ([identityData appGID] != nil))
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 将GID数据写入文件
+        NSString *appGIDPath = [documentDirectory stringByAppendingPathComponent:kAppGIDFile];
+        [[identityData appGID] writeToFile:appGIDPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        
+        if ([[NSFileManager defaultManager] respondsToSelector:@selector(containerURLForSecurityApplicationGroupIdentifier:)])
+        {
+            NSString *groupUrl = [[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[DataController getAppGroupID]] relativePath];
+            [[identityData appGID] writeToFile:[groupUrl stringByAppendingPathComponent:kAppGIDFile] atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        }
+    }
+}
+
+// 保存AppUID
+- (void)saveAppUID
+{
+    if((identityData != nil) && ([identityData appUID] != nil))
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 将UID数据写入文件
+        NSString *appUIDPath = [documentDirectory stringByAppendingPathComponent:kAppUIDFile];
+        [[identityData appUID] writeToFile:appUIDPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        
+        if ([[NSFileManager defaultManager] respondsToSelector:@selector(containerURLForSecurityApplicationGroupIdentifier:)])
+        {
+            NSString *groupUrl = [[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[DataController getAppGroupID]] relativePath];
+            [[identityData appUID] writeToFile:[groupUrl stringByAppendingPathComponent:kAppUIDFile] atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        }
+    }
+}
+
+// 保存ServerID
+- (void)saveServerID
+{
+    if((identityData != nil) && ([identityData serverID] != nil))
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 将ServerID数据写入文件
+        NSString *serverIDPath = [documentDirectory stringByAppendingPathComponent:kServerIDFile];
+        [[identityData serverID] writeToFile:serverIDPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        
+        if ([[NSFileManager defaultManager] respondsToSelector:@selector(containerURLForSecurityApplicationGroupIdentifier:)])
+        {
+            NSString *groupUrl = [[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[DataController getAppGroupID]] relativePath];
+            [[identityData serverID] writeToFile:[groupUrl stringByAppendingPathComponent:kServerIDFile] atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        }
+    }
+}
+
+// 保存UID
+- (void)saveDeviceUID
+{
+    if((identityData != nil) && ([identityData deviceUID] != nil))
+    {
+        // 获取document文件夹位置
+        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+        NSString *documentDirectory = [paths objectAtIndex:0];
+        
+        // 将DeviceUID数据写入文件
+        NSString *deviceUIDPath = [documentDirectory stringByAppendingPathComponent:kDeviceUIDFile];
+        [[identityData deviceUID] writeToFile:deviceUIDPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        
+        if ([[NSFileManager defaultManager] respondsToSelector:@selector(containerURLForSecurityApplicationGroupIdentifier:)])
+        {
+            NSString *groupUrl = [[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[DataController getAppGroupID]] relativePath];
+            [[identityData deviceUID] writeToFile:[groupUrl stringByAppendingPathComponent:kDeviceUIDFile] atomically:YES encoding:NSUTF8StringEncoding error:nil];
+        }
+    }
+}
+
+// 系统型号
++ (NSString *)osVersion {
+    return [[UIDevice currentDevice] systemVersion];
+}
+
+// 获取App的版本号,包含buildID, 如:1.0.0-3 其中1.0.0为appVersion,3位build ID
++ (NSString *)appVersion {
+     NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
+
+    
+    NSString *appVersion = [infoDic objectForKey:@"CFBundleShortVersionString"];
+
+    if(appVersion.length > 0) {
+        return [NSString stringWithFormat: @"%@-%@", appVersion, [self appBuildID]];
+    }
+
+    return @"";
+}
+
+// 获取build号
++ (NSString *)appBuildID {
+    NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
+    
+    
+    NSString *buildId = [infoDic objectForKey:@"CFBundleVersion"];
+    
+    if(buildId.length > 0) {
+        return buildId;
+    }
+    
+    return @"";
+}
+
++ (NSString *)deviceModelName
+{
+    struct utsname systemInfo;
+    
+    uname(&systemInfo);
+    
+    NSString* code = [NSString stringWithCString:systemInfo.machine
+                                        encoding:NSUTF8StringEncoding];
+    
+    static NSDictionary* deviceNamesByCode = nil;
+    
+    if (!deviceNamesByCode) {
+        
+        deviceNamesByCode = @{@"i386"      : @"Simulator",
+                              @"x86_64"    : @"Simulator",
+                              @"iPod1,1"   : @"iPod Touch",        // (Original)
+                              @"iPod2,1"   : @"iPod Touch",        // (Second Generation)
+                              @"iPod3,1"   : @"iPod Touch",        // (Third Generation)
+                              @"iPod4,1"   : @"iPod Touch",        // (Fourth Generation)
+                              @"iPod7,1"   : @"iPod Touch",        // (6th Generation)
+                              @"iPhone1,1" : @"iPhone",            // (Original)
+                              @"iPhone1,2" : @"iPhone",            // (3G)
+                              @"iPhone2,1" : @"iPhone",            // (3GS)
+                              @"iPad1,1"   : @"iPad",              // (Original)
+                              @"iPad2,1"   : @"iPad 2",            //
+                              @"iPad3,1"   : @"iPad",              // (3rd Generation)
+                              @"iPhone3,1" : @"iPhone 4",          // (GSM)
+                              @"iPhone3,3" : @"iPhone 4",          // (CDMA/Verizon/Sprint)
+                              @"iPhone4,1" : @"iPhone 4S",         //
+                              @"iPhone5,1" : @"iPhone 5",          // (model A1428, AT&T/Canada)
+                              @"iPhone5,2" : @"iPhone 5",          // (model A1429, everything else)
+                              @"iPad3,4"   : @"iPad",              // (4th Generation)
+                              @"iPad2,5"   : @"iPad Mini",         // (Original)
+                              @"iPhone5,3" : @"iPhone 5c",         // (model A1456, A1532 | GSM)
+                              @"iPhone5,4" : @"iPhone 5c",         // (model A1507, A1516, A1526 (China), A1529 | Global)
+                              @"iPhone6,1" : @"iPhone 5s",         // (model A1433, A1533 | GSM)
+                              @"iPhone6,2" : @"iPhone 5s",         // (model A1457, A1518, A1528 (China), A1530 | Global)
+                              @"iPhone7,1" : @"iPhone 6 Plus",     //
+                              @"iPhone7,2" : @"iPhone 6",          //
+                              @"iPhone8,1" : @"iPhone 6S",         //
+                              @"iPhone8,2" : @"iPhone 6S Plus",    //
+                              @"iPhone8,4" : @"iPhone SE",         //
+                              @"iPhone9,1" : @"iPhone 7",          //
+                              @"iPhone9,3" : @"iPhone 7",          //
+                              @"iPhone9,2" : @"iPhone 7 Plus",     //
+                              @"iPhone9,4" : @"iPhone 7 Plus",     //
+                              @"iPhone10,1": @"iPhone 8",          // CDMA
+                              @"iPhone10,4": @"iPhone 8",          // GSM
+                              @"iPhone10,2": @"iPhone 8 Plus",     // CDMA
+                              @"iPhone10,5": @"iPhone 8 Plus",     // GSM
+                              @"iPhone10,3": @"iPhone X",          // CDMA
+                              @"iPhone10,6": @"iPhone X",          // GSM
+                              
+                              @"iPad4,1"   : @"iPad Air",          // 5th Generation iPad (iPad Air) - Wifi
+                              @"iPad4,2"   : @"iPad Air",          // 5th Generation iPad (iPad Air) - Cellular
+                              @"iPad4,4"   : @"iPad Mini",         // (2nd Generation iPad Mini - Wifi)
+                              @"iPad4,5"   : @"iPad Mini",         // (2nd Generation iPad Mini - Cellular)
+                              @"iPad4,7"   : @"iPad Mini",         // (3rd Generation iPad Mini - Wifi (model A1599))
+                              @"iPad6,7"   : @"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1584)
+                              @"iPad6,8"   : @"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1652)
+                              @"iPad6,3"   : @"iPad Pro (9.7\")",  // iPad Pro 9.7 inches - (model A1673)
+                              @"iPad6,4"   : @"iPad Pro (9.7\")"   // iPad Pro 9.7 inches - (models A1674 and A1675)
+                              };
+    }
+    
+    NSString* deviceName = [deviceNamesByCode objectForKey:code];
+    
+    if (!deviceName) {
+        // Not found on database. At least guess main device type from string contents:
+        
+        if ([code rangeOfString:@"iPod"].location != NSNotFound) {
+            deviceName = @"iPod Touch";
+        }
+        else if([code rangeOfString:@"iPad"].location != NSNotFound) {
+            deviceName = @"iPad";
+        }
+        else if([code rangeOfString:@"iPhone"].location != NSNotFound){
+            deviceName = @"iPhone";
+        }
+        else {
+            deviceName = @"Unknown";
+        }
+    }
+    
+    return deviceName;
+}
+
++ (NSString *)bundleID {
+    return [[NSBundle mainBundle] bundleIdentifier];
+}
+
+// 用户所在的运营商
++ (id)getCarrierCode
+{
+    // 判断是否能够取得运营商
+    Class telephoneNetWorkClass = (NSClassFromString(@"CTTelephonyNetworkInfo"));
+    if (telephoneNetWorkClass != nil)
+    {
+        CTTelephonyNetworkInfo *telephonyNetworkInfo = [[CTTelephonyNetworkInfo alloc] init];
+        
+        // 获得运营商的信息
+        Class carrierClass = (NSClassFromString(@"CTCarrier"));
+        if (carrierClass != nil)
+        {
+            CTCarrier *carrier = telephonyNetworkInfo.subscriberCellularProvider;
+            
+            // 移动运营商的mcc 和 mnc
+            NSString * mobileCountryCode = [carrier mobileCountryCode];
+            NSString * mobileNetworkCode = [carrier mobileNetworkCode];
+            
+            // 统计能够取到信息的运营商
+            if ((mobileCountryCode != nil) && (mobileNetworkCode != nil))
+            {
+                NSString *mobileCode = [[NSString alloc] initWithFormat:@"%@%@", mobileCountryCode, mobileNetworkCode];
+                return mobileCode;
+            }
+        }
+    }
+    
+    return [NSNull null];
+}
+
+@end

+ 24 - 0
ios/CParam/IdentityData.h

@@ -0,0 +1,24 @@
+//
+//  IdentityData.h
+//  CParam
+//
+//  Created by breeze on 2017/6/20.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface IdentityData : NSObject
+
+@property (nonatomic, strong) NSString *appGID;                     // 客户端的Gid
+@property (nonatomic, strong) NSString *serverID;					// 服务器分配的ServerID
+@property (nonatomic, strong) NSString *deviceUID;                  // 机器的唯一标识
+@property (nonatomic, strong) NSString *appUID;                     // 客户端的Uid
+
+// 初始化函数
+- (id)init;
+
+// 销毁
+- (void)destroy;
+
+@end

+ 39 - 0
ios/CParam/IdentityData.m

@@ -0,0 +1,39 @@
+//
+//  IdentityData.m
+//  CParam
+//
+//  Created by breeze on 2017/6/20.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import "IdentityData.h"
+
+@implementation IdentityData
+
+// 初始化函数
+- (id)init
+{
+    if(self = [super init])
+    {
+        // 初始化数组
+        _appGID = nil;
+        _serverID = nil;
+        _deviceUID = nil;
+        _appUID = nil;
+        
+        return self;
+    }
+    
+    return nil;
+}
+
+// 销毁
+- (void)destroy
+{
+    _appGID = nil;
+    _serverID = nil;
+    _deviceUID = nil;
+    _appUID = nil;
+}
+
+@end

+ 29 - 0
ios/CParam/LocationManager.h

@@ -0,0 +1,29 @@
+//
+//  LocationManager.h
+//  CParam
+//
+//  Created by breeze deng on 2017/8/7.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
+
+@protocol LocationManagerDelegate <NSObject>
+
+@optional
+- (void)updateLocationWithCoordinate:(CLLocationCoordinate2D)coordinate;
+
+@end
+
+@interface LocationManager : NSObject
+
++ (LocationManager *)shareInstance;
+
+@property (nonatomic, weak) id<LocationManagerDelegate> delegate;
+
+- (void)startUpdatingLocation;
+
+- (void)stopUpdatingLocation;
+
+@end

+ 91 - 0
ios/CParam/LocationManager.m

@@ -0,0 +1,91 @@
+//
+//  LocationManager.m
+//  CParam
+//
+//  Created by breeze deng on 2017/8/7.
+//  Copyright © 2017年 Breeze. All rights reserved.
+//
+
+#import "LocationManager.h"
+
+static LocationManager *_instance = nil;
+
+@interface LocationManager () <CLLocationManagerDelegate>
+
+@property (nonatomic, strong) CLLocationManager* locationManager;
+
+@end
+
+@implementation LocationManager
+
++ (LocationManager *)shareInstance
+{
+    @synchronized(self)
+    {
+        // 实例对象只分配一次
+        if(_instance == nil)
+        {
+            _instance = [[super allocWithZone:NULL] init];
+        }
+    }
+    
+    return _instance;
+}
+
++ (id)allocWithZone:(NSZone *)zone
+{
+    return [self shareInstance];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    return self;
+}
+
+
+
+- (CLLocationManager *)locationManager {
+    if (_locationManager == nil) {
+        _locationManager = [[CLLocationManager alloc] init];
+        _locationManager.delegate = self;
+        _locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
+    }
+    
+    return _locationManager;
+}
+
+
+- (void)startUpdatingLocation
+{
+    if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
+        NSLog(@"requestWhenInUseAuthorization =======:");
+        [self.locationManager requestWhenInUseAuthorization];
+    }
+    
+    //开始定位,不断调用其代理方法
+    [self.locationManager startUpdatingLocation];
+}
+
+
+- (void)stopUpdatingLocation {
+    [self.locationManager stopUpdatingLocation];
+}
+
+- (void)locationManager:(CLLocationManager *)manager
+     didUpdateLocations:(NSArray *)locations
+{
+    // 1.获取用户位置的对象
+    CLLocation *location = [locations lastObject];
+    CLLocationCoordinate2D coordinate = location.coordinate;
+    
+    if ([self.delegate respondsToSelector: @selector(updateLocationWithCoordinate:)]) {
+        [self.delegate updateLocationWithCoordinate: coordinate];
+    }
+    
+    // 2.停止定位
+    [manager stopUpdatingLocation];
+}
+
+
+
+@end

+ 353 - 0
ios/CParam/SSKeychain/SSKeychain.h

@@ -0,0 +1,353 @@
+//
+//  SSKeychain.h
+//  SSToolkit
+//
+//  Created by Sam Soffes on 5/19/10.
+//  Copyright (c) 2009-2011 Sam Soffes. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <Security/Security.h>
+
+/** Error codes that can be returned in NSError objects. */
+typedef enum {
+	/** No error. */
+	SSKeychainErrorNone = noErr,
+	
+	/** Some of the arguments were invalid. */
+	SSKeychainErrorBadArguments = -1001,
+	
+	/** There was no password. */
+	SSKeychainErrorNoPassword = -1002,
+	
+	/** One or more parameters passed internally were not valid. */
+	SSKeychainErrorInvalidParameter = errSecParam,
+	
+	/** Failed to allocate memory. */
+	SSKeychainErrorFailedToAllocated = errSecAllocate,
+	
+	/** No trust results are available. */
+	SSKeychainErrorNotAvailable = errSecNotAvailable,
+	
+	/** Authorization/Authentication failed. */
+	SSKeychainErrorAuthorizationFailed = errSecAuthFailed,
+	
+	/** The item already exists. */
+	SSKeychainErrorDuplicatedItem = errSecDuplicateItem,
+	
+	/** The item cannot be found.*/
+	SSKeychainErrorNotFound = errSecItemNotFound,
+	
+	/** Interaction with the Security Server is not allowed. */
+	SSKeychainErrorInteractionNotAllowed = errSecInteractionNotAllowed,
+	
+	/** Unable to decode the provided data. */
+	SSKeychainErrorFailedToDecode = errSecDecode
+} SSKeychainErrorCode;
+
+extern NSString *const kSSKeychainErrorDomain;
+
+/** Account name. */
+extern NSString *const kSSKeychainAccountKey;
+
+/**
+ Time the item was created.
+ 
+ The value will be a string.
+ */
+extern NSString *const kSSKeychainCreatedAtKey;
+
+/** Item class. */
+extern NSString *const kSSKeychainClassKey;
+
+/** Item description. */
+extern NSString *const kSSKeychainDescriptionKey;
+
+/** Item label. */
+extern NSString *const kSSKeychainLabelKey;
+
+/** Time the item was last modified.
+ 
+ The value will be a string.
+ */
+extern NSString *const kSSKeychainLastModifiedKey;
+
+/** Where the item was created. */
+extern NSString *const kSSKeychainWhereKey;
+
+/**
+ Simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system
+ Keychain on Mac OS X and iOS.
+ 
+ This was originally inspired by EMKeychain and SDKeychain (both of which are now gone). Thanks to the authors.
+ SSKeychain has since switched to a simpler implementation that was abstracted from [SSToolkit](http://sstoolk.it).
+ */
+@interface SSKeychain : NSObject
+
+///-----------------------
+/// @name Getting Accounts
+///-----------------------
+
+/**
+ Returns an array containing the Keychain's accounts, or `nil` if the Keychain has no accounts.
+ 
+ See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the
+ dictionaries returned by this method.
+ 
+ @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any
+ accounts. The order of the objects in the array isn't defined.
+ 
+ @see allAccounts:
+ */
++ (NSArray *)allAccounts;
+
+/**
+ Returns an array containing the Keychain's accounts, or `nil` if the Keychain doesn't have any
+ accounts.
+ 
+ See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the
+ dictionaries returned by this method.
+ 
+ @param error If accessing the accounts fails, upon return contains an error that describes the problem.
+ 
+ @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any
+ accounts. The order of the objects in the array isn't defined.
+  
+ @see allAccounts
+ */
++ (NSArray *)allAccounts:(NSError **)error;
+
+/**
+ Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any
+ accounts for the given service.
+ 
+ See the `NSString` constants declared in SSKeychain.h for a list of keys that can be used when accessing the
+ dictionaries returned by this method.
+ 
+ @param serviceName The service for which to return the corresponding accounts.
+ 
+ @return An array of dictionaries containing the Keychain's accountsfor a given `serviceName`, or `nil` if the Keychain
+ doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined.
+ 
+ @see accountsForService:error:
+ */
++ (NSArray *)accountsForService:(NSString *)serviceName;
+
+/**
+ Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any
+ accounts for the given service.
+ 
+ @param serviceName The service for which to return the corresponding accounts.
+ 
+ @param error If accessing the accounts fails, upon return contains an error that describes the problem.
+ 
+ @return An array of dictionaries containing the Keychain's accountsfor a given `serviceName`, or `nil` if the Keychain
+ doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined.
+ 
+ @see accountsForService:
+ */
++ (NSArray *)accountsForService:(NSString *)serviceName error:(NSError **)error;
+
+
+///------------------------
+/// @name Getting Passwords
+///------------------------
+
+/**
+ Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a
+ password for the given parameters.
+ 
+ @param serviceName The service for which to return the corresponding password.
+ 
+ @param account The account for which to return the corresponding password.
+ 
+ @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't
+ have a password for the given parameters.
+ 
+ @see passwordForService:account:error:
+ */
++ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;
+
+/**
+ Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a
+ password for the given parameters.
+ 
+ @param serviceName The service for which to return the corresponding password.
+ 
+ @param account The account for which to return the corresponding password.
+ 
+ @param error If accessing the password fails, upon return contains an error that describes the problem.
+ 
+ @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't
+ have a password for the given parameters.
+ 
+ @see passwordForService:account:
+ */
++ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error;
+
+/**
+ Returns the password data for a given account and service, or `nil` if the Keychain doesn't have data 
+ for the given parameters.
+ 
+ @param serviceName The service for which to return the corresponding password.
+ 
+ @param account The account for which to return the corresponding password.
+ 
+ @return Returns a the password data for the given account and service, or `nil` if the Keychain doesn't
+ have data for the given parameters.
+ 
+ @see passwordDataForService:account:error:
+ */
++ (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account;
+
+/**
+ Returns the password data for a given account and service, or `nil` if the Keychain doesn't have data 
+ for the given parameters.
+ 
+ @param serviceName The service for which to return the corresponding password.
+ 
+ @param account The account for which to return the corresponding password.
+ 
+ @param error If accessing the password fails, upon return contains an error that describes the problem.
+ 
+ @return Returns a the password data for the given account and service, or `nil` if the Keychain doesn't
+ have a password for the given parameters.
+ 
+ @see passwordDataForService:account:
+ */
++ (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error;
+
+
+///-------------------------
+/// @name Deleting Passwords
+///-------------------------
+
+/**
+ Deletes a password from the Keychain.
+ 
+ @param serviceName The service for which to delete the corresponding password.
+ 
+ @param account The account for which to delete the corresponding password.
+ 
+ @return Returns `YES` on success, or `NO` on failure.
+ 
+ @see deletePasswordForService:account:error:
+ */
++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;
+
+/**
+ Deletes a password from the Keychain.
+ 
+ @param serviceName The service for which to delete the corresponding password.
+ 
+ @param account The account for which to delete the corresponding password.
+ 
+ @param error If deleting the password fails, upon return contains an error that describes the problem.
+ 
+ @return Returns `YES` on success, or `NO` on failure.
+ 
+ @see deletePasswordForService:account:
+ */
++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error;
+
+
+///------------------------
+/// @name Setting Passwords
+///------------------------
+
+/**
+ Sets a password in the Keychain.
+ 
+ @param password The password to store in the Keychain.
+ 
+ @param serviceName The service for which to set the corresponding password.
+ 
+ @param account The account for which to set the corresponding password.
+ 
+ @return Returns `YES` on success, or `NO` on failure.
+ 
+ @see setPassword:forService:account:error:
+ */
++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;
+
+/**
+ Sets a password in the Keychain.
+ 
+ @param password The password to store in the Keychain.
+ 
+ @param serviceName The service for which to set the corresponding password.
+ 
+ @param account The account for which to set the corresponding password.
+ 
+ @param error If setting the password fails, upon return contains an error that describes the problem.
+ 
+ @return Returns `YES` on success, or `NO` on failure.
+ 
+ @see setPassword:forService:account:
+ */
++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error;
+
+/**
+ Sets arbirary data in the Keychain.
+ 
+ @param password The data to store in the Keychain.
+ 
+ @param serviceName The service for which to set the corresponding password.
+ 
+ @param account The account for which to set the corresponding password.
+ 
+ @return Returns `YES` on success, or `NO` on failure.
+ 
+ @see setPasswordData:forService:account:error:
+ */
++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account;
+
+/**
+ Sets arbirary data in the Keychain.
+ 
+ @param password The data to store in the Keychain.
+ 
+ @param serviceName The service for which to set the corresponding password.
+ 
+ @param account The account for which to set the corresponding password.
+ 
+ @param error If setting the password fails, upon return contains an error that describes the problem.
+ 
+ @return Returns `YES` on success, or `NO` on failure.
+ 
+ @see setPasswordData:forService:account:
+ */
++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error;
+
+
+///--------------------
+/// @name Configuration
+///--------------------
+
+#if __IPHONE_4_0 && TARGET_OS_IPHONE
+/**
+ Returns the accessibility type for all future passwords saved to the Keychain.
+ 
+ @return Returns the accessibility type.
+ 
+ The return value will be `NULL` or one of the "Keychain Item Accessibility Constants" used for determining when a
+ keychain item should be readable.
+ 
+ @see accessibilityType
+ */
++ (CFTypeRef)accessibilityType;
+
+/**
+ Sets the accessibility type for all future passwords saved to the Keychain.
+ 
+ @param accessibilityType One of the "Keychain Item Accessibility Constants" used for determining when a keychain item
+ should be readable.
+ 
+ If the value is `NULL` (the default), the Keychain default will be used.
+ 
+ @see accessibilityType
+ */
++ (void)setAccessibilityType:(CFTypeRef)accessibilityType;
+#endif
+
+@end

+ 262 - 0
ios/CParam/SSKeychain/SSKeychain.m

@@ -0,0 +1,262 @@
+//
+//  SSKeychain.m
+//  SSToolkit
+//
+//  Created by Sam Soffes on 5/19/10.
+//  Copyright (c) 2009-2011 Sam Soffes. All rights reserved.
+//
+
+#import "SSKeychain.h"
+
+NSString *const kSSKeychainErrorDomain = @"com.samsoffes.sskeychain";
+
+NSString *const kSSKeychainAccountKey = @"acct";
+NSString *const kSSKeychainCreatedAtKey = @"cdat";
+NSString *const kSSKeychainClassKey = @"labl";
+NSString *const kSSKeychainDescriptionKey = @"desc";
+NSString *const kSSKeychainLabelKey = @"labl";
+NSString *const kSSKeychainLastModifiedKey = @"mdat";
+NSString *const kSSKeychainWhereKey = @"svce";
+
+#if __IPHONE_4_0 && TARGET_OS_IPHONE  
+CFTypeRef SSKeychainAccessibilityType = NULL;
+#endif
+
+@interface SSKeychain ()
++ (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account;
+@end
+
+@implementation SSKeychain
+
+#pragma mark - Getting Accounts
+
++ (NSArray *)allAccounts {
+    return [self accountsForService:nil error:nil];
+}
+
+
++ (NSArray *)allAccounts:(NSError **)error {
+    return [self accountsForService:nil error:error];
+}
+
+
++ (NSArray *)accountsForService:(NSString *)service {
+    return [self accountsForService:service error:nil];
+}
+
+
++ (NSArray *)accountsForService:(NSString *)service error:(NSError **)error {
+    OSStatus status = SSKeychainErrorBadArguments;
+    NSMutableDictionary *query = [self _queryForService:service account:nil];
+#if __has_feature(objc_arc)
+	[query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
+    [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
+#else
+    [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
+    [query setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit];
+#endif
+	
+	CFTypeRef result = NULL;
+#if __has_feature(objc_arc)
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
+#else
+	status = SecItemCopyMatching((CFDictionaryRef)query, &result);
+#endif
+    if (status != noErr && error != NULL) {
+		*error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
+		return nil;
+	}
+	
+#if __has_feature(objc_arc)
+	return (__bridge_transfer NSArray *)result;
+#else
+    return [(NSArray *)result autorelease];
+#endif
+}
+
+
+#pragma mark - Getting Passwords
+
++ (NSString *)passwordForService:(NSString *)service account:(NSString *)account {
+	return [self passwordForService:service account:account error:nil];
+}
+
+
++ (NSString *)passwordForService:(NSString *)service account:(NSString *)account error:(NSError **)error {
+    NSData *data = [self passwordDataForService:service account:account error:error];
+	if (data.length > 0) {
+		NSString *string = [[NSString alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding];
+#if !__has_feature(objc_arc)
+		[string autorelease];
+#endif
+		return string;
+	}
+	
+	return nil;
+}
+
+
++ (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account {
+    return [self passwordDataForService:service account:account error:nil];
+}
+
+
++ (NSData *)passwordDataForService:(NSString *)service account:(NSString *)account error:(NSError **)error {
+    OSStatus status = SSKeychainErrorBadArguments;
+	if (!service || !account) {
+		if (error) {
+			*error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
+		}
+		return nil;
+	}
+	
+	CFTypeRef result = NULL;	
+	NSMutableDictionary *query = [self _queryForService:service account:account];
+#if __has_feature(objc_arc)
+	[query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
+	[query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
+	status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
+#else
+	[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
+	[query setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
+	status = SecItemCopyMatching((CFDictionaryRef)query, &result);
+#endif
+	
+	if (status != noErr && error != NULL) {
+		*error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
+		return nil;
+	}
+	
+#if __has_feature(objc_arc)
+	return (__bridge_transfer NSData *)result;
+#else
+    return [(NSData *)result autorelease];
+#endif
+}
+
+
+#pragma mark - Deleting Passwords
+
++ (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account {
+	return [self deletePasswordForService:service account:account error:nil];
+}
+
+
++ (BOOL)deletePasswordForService:(NSString *)service account:(NSString *)account error:(NSError **)error {
+	OSStatus status = SSKeychainErrorBadArguments;
+	if (service && account) {
+		NSMutableDictionary *query = [self _queryForService:service account:account];
+#if __has_feature(objc_arc)
+		status = SecItemDelete((__bridge CFDictionaryRef)query);
+#else
+		status = SecItemDelete((CFDictionaryRef)query);
+#endif
+	}
+	if (status != noErr && error != NULL) {
+		*error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
+	}
+	return (status == noErr);
+    
+}
+
+
+#pragma mark - Setting Passwords
+
++ (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account {
+	return [self setPassword:password forService:service account:account error:nil];
+}
+
+
++ (BOOL)setPassword:(NSString *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error {
+    NSData *data = [password dataUsingEncoding:NSUTF8StringEncoding];
+    return [self setPasswordData:data forService:service account:account error:error];
+}
+
+
++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account {
+    return [self setPasswordData:password forService:service account:account error:nil];
+}
+
+
++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)service account:(NSString *)account error:(NSError **)error {
+    OSStatus status = SSKeychainErrorBadArguments;
+	if (password && service && account) {
+        [self deletePasswordForService:service account:account];
+        NSMutableDictionary *query = [self _queryForService:service account:account];
+#if __has_feature(objc_arc)
+		[query setObject:password forKey:(__bridge id)kSecValueData];
+#else
+		[query setObject:password forKey:(id)kSecValueData];
+#endif
+		
+#if __IPHONE_4_0 && TARGET_OS_IPHONE
+		if (SSKeychainAccessibilityType) {
+#if __has_feature(objc_arc)
+			[query setObject:(id)[self accessibilityType] forKey:(__bridge id)kSecAttrAccessible];
+#else
+			[query setObject:(id)[self accessibilityType] forKey:(id)kSecAttrAccessible];
+#endif
+		}
+#endif
+		
+#if __has_feature(objc_arc)
+        status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
+#else
+		status = SecItemAdd((CFDictionaryRef)query, NULL);
+#endif
+	}
+	if (status != noErr && error != NULL) {
+		*error = [NSError errorWithDomain:kSSKeychainErrorDomain code:status userInfo:nil];
+	}
+	return (status == noErr);
+}
+
+
+#pragma mark - Configuration
+
+#if __IPHONE_4_0 && TARGET_OS_IPHONE 
++ (CFTypeRef)accessibilityType {
+	return SSKeychainAccessibilityType;
+}
+
+
++ (void)setAccessibilityType:(CFTypeRef)accessibilityType {
+	CFRetain(accessibilityType);
+	if (SSKeychainAccessibilityType) {
+		CFRelease(SSKeychainAccessibilityType);
+	}
+	SSKeychainAccessibilityType = accessibilityType;
+}
+#endif
+
+
+#pragma mark - Private
+
++ (NSMutableDictionary *)_queryForService:(NSString *)service account:(NSString *)account {
+    NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3];
+#if __has_feature(objc_arc)
+    [dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
+#else
+	[dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
+#endif
+	
+    if (service) {
+#if __has_feature(objc_arc)
+		[dictionary setObject:service forKey:(__bridge id)kSecAttrService];
+#else
+		[dictionary setObject:service forKey:(id)kSecAttrService];
+#endif
+	}
+	
+    if (account) {
+#if __has_feature(objc_arc)
+		[dictionary setObject:account forKey:(__bridge id)kSecAttrAccount];
+#else
+		[dictionary setObject:account forKey:(id)kSecAttrAccount];
+#endif
+	}
+	
+    return dictionary;
+}
+
+@end

+ 11 - 0
package.json

@@ -0,0 +1,11 @@
+{
+  "name": "cparam",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "brilliantaero",
+  "license": "MIT"
+}