diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..449c850 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +.tern_port +/node_modules/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index 37859fc..d46a0cf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Derek Hsu +Copyright (c) 2015 Xinyu Zhang, Derek Hsu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6bcc3cd..f9ad3b6 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,262 @@ -cordova-plugin-lean-push +cordova-plugin-leanpush ======================== -Cordova plugin for LeanCloud push notification +Cordova plugin for [LeanCloud](https://leancloud.cn) push notification + + ## Installation + + +- Fetch from cordova npm + +```shell + cordova plugin add cordova-plugin-leanpush --variable LEAN_APP_ID= --variable LEAN_APP_KEY= +``` + + + + +- Add this to your `gulpfile.js` + +```js +gulp.task('lpush-install', function(done){ + require('./plugins/cordova-plugin-leanpush/lpush-installer.js')(__dirname, done); +}); +``` + +- `npm install --save-dev xml2js thunks && npm install` + +- Then exectue this gulp task by running `gulp lpush-install` in shell. + +- Done. + +### Known Android Build Issue + +See [Attention/Android Build Issue](#android-build-issue) + + + +## Usage + +### Init + + +Put the initialization Code in your "deviceReady" Code Block (like $ionicPlatform.ready) + +```js +window.LeanPush.init(); +``` + + + + + +### Push Related API + + +Coresponding to the [Leancloud Push documentation](https://leancloud.cn/docs/ios_push_guide.html). + +```js + +window.LeanPush.subscribe(channel, success, error) // 订阅频道 channel :string +window.LeanPush.unsubscribe(channel, success, error) //退订频道 channel :string +window.LeanPush.clearSubscription(success, error) //退订所有频道 + +window.LeanPush.getInstallation(success, error) //Installation 表示一个允许推送的设备的唯一标示, 对应数据管理平台中的 _Installation 表 +// success callback: +// function(data){ +// data = { +// 'deviceType':'android' or 'ios', +// 'installationId': 'android installation id' or 'ios deviceToken' +// 'deviceToken': 'ios deviceToken' or 'android installation id' +// } +// } + + +window.LeanPush.onNotificationReceived(callback) // 一个notification到来的回调函数 +// callback: +// function(notice){ +// notice = { +// 'prevAppState': 'background' or 'foreground' or 'closed', + +// push到来的时候上一个App状态: +// android只有 'background' 和 'closed', 因为android所有push都要点击 +// ios都有,因为ios如果app在前台,系统推送的alert不会出现 +// 用户没有任何操作,app就自动执行notification的函数不好, 可以加个判断 + +// 'alert':'Notice Text', +// 'file_url':'Push File', +// 'key':'value' if you send JSON Type Push, they will map to here. +// } +// } - cordova plugin add git@github.com:Hybrid-Force/cordova-plugin-leancloud.git --variable LEAN_APP_ID= --variable LEAN_APP_KEY= - -## Android Quirk -The LeanCloud push service need to be initialized in Application::onCreate, otherwise, the app might crash when opening via push notification when the app is not running in foreground. To fix this, add an application where we can initialize the push service. - -1. Edit `platforms/android/src/com/sum/cordova/leancloud/LeanApplication.java`, replace `<%MAINACTIVITY%>`, `<%APPID%>` and `<%APPKEY%>`. - -2. Edit `platforms/android/AndroidManifest.xml`, add `android:name="com.sum.cordova.leancloud.LeanApplication"` to application element - -These can be easily done with gulp, for example: - - var xeditor = require('gulp-xml-editor'); - var replace = require('gulp-replace'); - var config = require('./package.json'); - - gulp.task('android-manifest', function() { - return gulp.src("platforms/android/AndroidManifest.xml") - .pipe(xeditor([ - { - path: '/manifest/application', - attr: {'android:name': 'com.sum.cordova.leancloud.LeanApplication'} - }], {'android': 'http://schemas.android.com/apk/res/android'})) - .pipe(gulp.dest("platforms/android")); - }); - - gulp.task('android-application', function() { - return gulp.src("platforms/android/src/com/sum/cordova/leancloud/LeanApplication.java") - .pipe(replace('<%MAINACTIVITY%>', config.mainActivity)) - .pipe(replace('<%APPID%>', config.leanAppId)) - .pipe(replace('<%APPKEY%>', config.leanAppKey)) - .pipe(gulp.dest("platforms/android/src/com/sum/cordova/leancloud")); - }); + +$rootScope.$on('leancloud:notificationReceived', callback) // 如果你用了angular, 一个notification会在scope上broadcast这个event +// callback: +// function(event, notice){ +// // event is from angular, notice is same above +// } +``` + +Many Thanks to [Derek Hsu](https://github.com/Hybrid-Force) XD 😁 + + + + +### About Sending Push + +Use the [JS API: AV.Push](https://leancloud.cn/docs/js_guide.html#Push_通知) that leancloud provide. + + + +### LeanAnalytics API + +Corresponding code is forked from [https://github.com/Hybrid-Force/cordova-plugin-leancloud](https://github.com/Hybrid-Force/cordova-plugin-leancloud). + + +Only a novice for leancloud I am, so + +- take a look at the source code [https://github.com/BenBBear/cordova-plugin-leanpush/blob/master/www/LeanAnalytics.js](https://github.com/BenBBear/cordova-plugin-leanpush/blob/master/www/LeanAnalytics.js) to know the API + +- and study the [Leancloud documentation about leanAnalytics](https://leancloud.cn/docs/ios_statistics.html) + +is the better way to go. + + + +--- + +## Screen Recording + +### Android +![](./img/android.gif) + +### IOS + +See the [Attention Below](#attention), the webview can't `alert` when `onResume` + +#### One + +- notice from close +- notice while foreground + +![](./img/ios.gif) + +#### Two + +- notice from background + +##### mobile + +![](./img/ios-back-phone.gif) + +##### console.log + +![](./img/ios-back.gif) + +The debugger in screenshot is [GapDebug](https://www.genuitec.com/products/gapdebug/), debug phonegap in browser :D + + + + + + +## Behavior + +The `onNotificationReceived callback` and the `$rootScope.$emit('leancloud:notificationReceived')` will fires when + +### IOS + +- app in the foreground, notice comes (won't show the system notification alert) +- app in the background, tap the notification to resume it +- app closed, tap the notification to open it + +### Android + + +- app in the foreground, tap the notification to see it +- app in the background, tap the notification to resume it +- app closed, tap the notification to open it + + + +## Attention + +### Android Quirk + +In order to receive push from android, I change the default `MainActivity` and `Application Entry` in that gulp task. Details in the [lpush_installer.js](https://github.com/BenBBear/cordova-plugin-leanpush/blob/master/lpush-installer.js). + +> So if you use another plugin that also goes this way, then there gonna be conflicts. + + +#### Uninstall + +For fully uninstallation: + +```shell +cordova plugin rm cordova-plugin-leanpush +ionic platform rm android && ionic platform rm ios +ionic platform add android && ionic platform add ios +``` + +### Don't Use Alert in the IOS inside Notification Callback + +> `alert` is a blocking function. + +#### IOS UIWebView + +It will cause the app to freeze when you resume the app by clicking notification. (but it seems ok when the app is in the foreground or closed.) + +### For Android + +As far as I try, `alert` is fine, guess is the difference of webView between IOS and android. + + +### Notification Handler + +There are two ways, both will be fired when notification comes + +- `onNotificationReceived` + +- `$rootScope.$emit('leancloud:notificationReceived')` + + +You can choose one of them, but may not both. + + +### Android Build Issue + +- **Error: duplicate files during packaging of APK** + +**How to Solve:** + + +insert following code into the **android tag** of `platforms/android/build.gradle` + +```groovy + packagingOptions { + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' +} +``` + +It should look like below + +```groovy +android{ + packagingOptions { + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } + //stuff +} +``` + + + +## LICENSE + +The MIT License (MIT) + +Copyright (c) 2015 Xinyu Zhang, Derek Hsu diff --git a/img/android.gif b/img/android.gif new file mode 100644 index 0000000..5a1d78d Binary files /dev/null and b/img/android.gif differ diff --git a/img/ios-back-phone.gif b/img/ios-back-phone.gif new file mode 100644 index 0000000..ba4264b Binary files /dev/null and b/img/ios-back-phone.gif differ diff --git a/img/ios-back.gif b/img/ios-back.gif new file mode 100644 index 0000000..0c5a014 Binary files /dev/null and b/img/ios-back.gif differ diff --git a/img/ios.gif b/img/ios.gif new file mode 100644 index 0000000..ce601d8 Binary files /dev/null and b/img/ios.gif differ diff --git a/lpush-installer.js b/lpush-installer.js new file mode 100644 index 0000000..db744af --- /dev/null +++ b/lpush-installer.js @@ -0,0 +1,144 @@ +var path = require('path'); +var fs = require('fs'); + +// For xml parsing +var xml2js = require('xml2js'); +var parser = new xml2js.Parser(); +var builder = new xml2js.Builder(); + +// Use Thunk instead of Callback +var thunks = require('thunks'); +var thunk = thunks({ + onerror: function(error) { + console.error('Error happens during installing cordova-plugin-leanpush, in the lpush-installer.js \n'); + console.error(error.message); + console.error(error.stack); + } +}); + +// Thunkify Function +var readFile = thunk.thunkify(fs.readFile), + writeFile = thunk.thunkify(fs.writeFile), + parseString = thunk.thunkify(parser.parseString), + as = thunk.thunkify(function(x, cb) { + cb(null, x); + }); + + + + + + +// get APPID & APPKEY & PACKAGE_NAME +function getVariables(root) { + + var android_config_xml = path.join(root, 'platforms/android/res/xml/config.xml'); + + return readFile(android_config_xml)(function(err, data) { + if (err) + throw err; + + return parseString(data.toString()); + + })(function(err, result) { + if (err) + throw err; + + var app_id, app_key, package_name; + package_name = result.widget.$.id; + result.widget.preference.forEach(function(item) { + if (item.$.name == 'leancloud-appid') { + app_id = item.$.value; + } + if (item.$.name == 'leancloud-appkey') { + app_key = item.$.value; + } + }); + + return as({ + app_id: app_id, + app_key: app_key, + package_name: package_name + }); + }); +} + + +// use Variables to patch source +function patchSource(vars) { + var root = vars.root; + + var lean_application_path = path.join(root, "platforms/android/src/me/xyzhang/cordova/leanpush/LeanApplication.java"), + android_manifest_path = path.join(root, "platforms/android/AndroidManifest.xml"), + lpush_main_activity_path = path.join(root, 'plugins/cordova-plugin-leanpush/other/MainActivity.java'); + + var app_id = vars.app_id, + app_key = vars.app_key, + package_name = vars.package_name; + + + + + return readFile(android_manifest_path)(function(err, data) { + if (err) + throw err; + return parseString(data.toString()); + })(function(err, result) { + if (err) + throw err; + + result.manifest.application[0].$['android:name'] = 'me.xyzhang.cordova.leanpush.LeanApplication'; + var xml = builder.buildObject(result); + return writeFile(android_manifest_path, xml); + })(function(err) { + if (err) + throw err; + + return readFile(lean_application_path); + })(function(err, data) { + if (err) + throw err; + + var source = data + .toString() + .replace('<%LEAN_APP_ID%>', app_id) + .replace('<%LEAN_APP_KEY%>', app_key) + .replace('<%PACKAGE_NAME%>', package_name); + return writeFile(lean_application_path, source); + })(function(err) { + if (err) + throw err; + return readFile(lpush_main_activity_path); + })(function(err, data){ + if(err) + throw err; + + var main_activity_dir_path = path.join(root, 'platforms/android/src/'); + + package_name + .split('.') + .forEach(function(name) { + main_activity_dir_path = path.join(main_activity_dir_path, name); + }); + + var source = data + .toString() + .replace('<%PACKAGE_NAME%>', package_name); + + return writeFile(path.join(main_activity_dir_path, 'MainActivity.java'), source); + }); +} + + + + +module.exports = function(root, done) { + getVariables(root)(function(err, vars){ + vars.root = root; + return patchSource(vars); + })(function(err){ + if(err) + throw err; + done(); + }); +}; diff --git a/other/MainActivity.java b/other/MainActivity.java new file mode 100644 index 0000000..b006ff7 --- /dev/null +++ b/other/MainActivity.java @@ -0,0 +1,74 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +package <%PACKAGE_NAME%>; + + +import android.content.ComponentName; +import android.app.ActivityManager; +import me.xyzhang.cordova.leanpush.LeanPush; +import android.os.Bundle; +import org.apache.cordova.*; +import java.util.List; +import com.avos.avoscloud.PushService; +import com.avos.avoscloud.AVInstallation; +import com.avos.avoscloud.AVOSCloud; + + +import android.app.Activity; +import android.content.Intent; + +public class MainActivity extends CordovaActivity +{ + + + + private void checkAndSend(final String where, final String status){ + Bundle extras = getIntent().getExtras(); + if (extras != null) { + String data = extras.getString("com.avos.avoscloud.Data"); + if(data !=null){ + getIntent().removeExtra("com.avos.avoscloud.Data"); + LeanPush.sendJsonString(data, status); + } + } + } + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + loadUrl(launchUrl); + this.checkAndSend("onCreate","closed"); + } + + @Override + protected void onResume() { + super.onResume(); + this.checkAndSend("onResume","background"); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + + + } + +} diff --git a/package.json b/package.json index b6de212..ef42b42 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { - "name": "cordova-plugin-leancloud", - "version": "0.1.1", + "name": "cordova-plugin-leanpush", + "version": "0.3.5", "description": "A Cordova plugin for LeanCloud Push and Analytics services", "cordova": { - "id": "cordova-plugin-leancloud", + "id": "cordova-plugin-leanpush", "platforms": [ "ios", "android" @@ -11,7 +11,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/Hybrid-Force/cordova-plugin-leancloud.git" + "url": "git+https://github.com/BenBBear/cordova-plugin-leanpush.git" }, "keywords": [ "ecosystem:cordova", @@ -21,10 +21,14 @@ "push", "analytics" ], - "author": "Derek Hsu", + "author": "Xinyu Zhang", "license": "MIT", "bugs": { - "url": "https://github.com/Hybrid-Force/cordova-plugin-leancloud/issues" + "url": "https://github.com/BenBBear/cordova-plugin-leanpush/issues" }, - "homepage": "https://github.com/Hybrid-Force/cordova-plugin-leancloud#readme" + "homepage": "https://github.com/BenBBear/cordova-plugin-leanpush", + "devDependencies": { + "thunks": "^3.5.1", + "xml2js": "^0.4.12" + } } diff --git a/plugin.xml b/plugin.xml index c1f30f2..0b72f87 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,15 +1,15 @@ - Cordova LeanCloud + id="cordova-plugin-leanpush" version="0.3.4"> + Cordova LeanCloud Push - + @@ -36,21 +36,25 @@ + + + + - + - + @@ -74,14 +78,14 @@ - - - + + + - - - + + + diff --git a/src/android/LeanAnalytics.java b/src/android/LeanAnalytics.java index b1ab4fd..a299147 100644 --- a/src/android/LeanAnalytics.java +++ b/src/android/LeanAnalytics.java @@ -1,4 +1,4 @@ -package com.sum.cordova.leancloud; +package me.xyzhang.cordova.leanpush; import java.util.HashMap; diff --git a/src/android/LeanApplication.java b/src/android/LeanApplication.java index 488d63a..6b15f47 100644 --- a/src/android/LeanApplication.java +++ b/src/android/LeanApplication.java @@ -1,4 +1,4 @@ -package com.sum.cordova.leancloud; +package me.xyzhang.cordova.leanpush; import android.app.Application; import android.content.Context; @@ -8,9 +8,9 @@ import com.avos.avoscloud.AVOSCloud; import com.avos.avoscloud.AVAnalytics; -import <%MAINACTIVITY%>; +import <%PACKAGE_NAME%>.MainActivity; -public class LeanApplication extends Application +public class LeanApplication extends Application { private static LeanApplication instance = new LeanApplication(); @@ -26,9 +26,11 @@ public static Context getContext() { public void onCreate() { super.onCreate(); // register device for leancloud - AVOSCloud.initialize(this, "<%APPID%>", "<%APPKEY%>"); - PushService.setDefaultPushCallback(this, MainActivity.class); + AVOSCloud.initialize(this, "<%LEAN_APP_ID%>", "<%LEAN_APP_KEY%>"); AVInstallation.getCurrentInstallation().saveInBackground(); - AVAnalytics.enableCrashReport(this, true); + PushService.setDefaultPushCallback(this, MainActivity.class); + AVAnalytics.enableCrashReport(this.getApplicationContext(), true); + AVOSCloud.setLastModifyEnabled(true); + AVOSCloud.setDebugLogEnabled(true); } -} \ No newline at end of file +} diff --git a/src/android/LeanPush.java b/src/android/LeanPush.java index 8f651ab..fd897d7 100644 --- a/src/android/LeanPush.java +++ b/src/android/LeanPush.java @@ -1,4 +1,4 @@ -package com.sum.cordova.leancloud; +package me.xyzhang.cordova.leanpush; import java.util.Arrays; import java.util.ArrayList; @@ -27,20 +27,20 @@ public class LeanPush extends CordovaPlugin { public static final String ACTION_SUBSCRIBE = "subscribe"; public static final String ACTION_UNSUBSCRIBE = "unsubscribe"; public static final String ACTION_CLEAR_SUBSCRIPTION = "clearSubscription"; + public static final String ACTION_GET_INSTALLTION = "getInstallation"; + public static final String ACTION_ON_NOTIFICATION_RECEIVED = "onNotificationReceived"; + private static CordovaWebView mWebView; + private static String callback; + private static String cacheResult; + @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); - - // String appId = this.preferences.getString(PROP_KEY_LEANCLOUD_APP_ID, ""); - // String appKey = this.preferences.getString(PROP_KEY_LEANCLOUD_APP_KEY, ""); - - // if (appId != null && !appId.isEmpty() && - // appKey != null && !appKey.isEmpty()) { - // AVOSCloud.initialize(cordova.getActivity(), appId, appKey); - // PushService.setDefaultPushCallback(cordova.getActivity(), cordova.getActivity().getClass()); - // AVInstallation.getCurrentInstallation().saveInBackground(); - // } + mWebView = webView; + if(cacheResult != null){ + sendJsonString(cacheResult, "closed"); + } } @Override @@ -57,35 +57,80 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo this.clearSubscription(callbackContext); return true; } + if(action.equals(ACTION_GET_INSTALLTION)){ + this.getInstallation(callbackContext); + return true; + } + if(action.equals(ACTION_ON_NOTIFICATION_RECEIVED)){ + onNotificationReceived(args.getString(0), callbackContext); + return true; + } + if(action.equals("getCacheResult")){ + getCacheResult(callbackContext); + return true; + } + return false; } + private static void onNotificationReceived(final String cb, final CallbackContext callbackContext){ + callback = cb; + callbackContext.success(); + } + + private void getInstallation(final CallbackContext callbackContext) { + String installationId = AVInstallation.getCurrentInstallation().getInstallationId(); + if (installationId == null) { + callbackContext.error("Fail to get Installation."); + } else { + callbackContext.success("android," + installationId); + } + } + private void subscribe(final String channel, final CallbackContext callbackContext) { cordova.getThreadPool().execute(new Runnable() { - public void run() { - PushService.subscribe(cordova.getActivity(), channel, cordova.getActivity().getClass()); - callbackContext.success(); - } - }); + public void run() { + PushService.subscribe(cordova.getActivity(), channel, cordova.getActivity().getClass()); + callbackContext.success(); + } + }); } private void unsubscribe(final String channel, final CallbackContext callbackContext) { cordova.getThreadPool().execute(new Runnable() { - public void run() { - PushService.unsubscribe(cordova.getActivity(), channel); - callbackContext.success(); - } - }); + public void run() { + PushService.unsubscribe(cordova.getActivity(), channel); + callbackContext.success(); + } + }); } private void clearSubscription(final CallbackContext callbackContext) { cordova.getThreadPool().execute(new Runnable() { - public void run() { - AVInstallation currentInstallation = AVInstallation.getCurrentInstallation(); - currentInstallation.put("channels", new ArrayList()); - currentInstallation.saveInBackground(); - callbackContext.success(); - } - }); + public void run() { + AVInstallation currentInstallation = AVInstallation.getCurrentInstallation(); + currentInstallation.put("channels", new ArrayList()); + currentInstallation.saveInBackground(); + callbackContext.success(); + } + }); + } + + private static void send(final String x, final String status){ + mWebView.loadUrl("javascript:" + callback +"('" + x + "', '" + status + "');"); + } + + + public static void sendJsonString(final String x, final String status){ + if(mWebView != null && callback != null){ + send(x, status); + cacheResult = null; + }else{ + cacheResult = x; + } + } + + private void getCacheResult(final CallbackContext callbackContext){ + callbackContext.success(cacheResult); } } diff --git a/src/android/leancloud/avoscloud-push-v3.1.4.jar b/src/android/leancloud/avoscloud-push-v3.3.jar old mode 100755 new mode 100644 similarity index 66% rename from src/android/leancloud/avoscloud-push-v3.1.4.jar rename to src/android/leancloud/avoscloud-push-v3.3.jar index 3b38f7d..d6aed08 Binary files a/src/android/leancloud/avoscloud-push-v3.1.4.jar and b/src/android/leancloud/avoscloud-push-v3.3.jar differ diff --git a/src/android/leancloud/avoscloud-sdk-v3.1.4.jar b/src/android/leancloud/avoscloud-sdk-v3.3.jar old mode 100755 new mode 100644 similarity index 62% rename from src/android/leancloud/avoscloud-sdk-v3.1.4.jar rename to src/android/leancloud/avoscloud-sdk-v3.3.jar index bf059c6..ac31f92 Binary files a/src/android/leancloud/avoscloud-sdk-v3.1.4.jar and b/src/android/leancloud/avoscloud-sdk-v3.3.jar differ diff --git a/src/android/leancloud/avoscloud-statistics-v3.1.4.jar b/src/android/leancloud/avoscloud-statistics-v3.3.jar old mode 100755 new mode 100644 similarity index 82% rename from src/android/leancloud/avoscloud-statistics-v3.1.4.jar rename to src/android/leancloud/avoscloud-statistics-v3.3.jar index ff4797d..23c4a20 Binary files a/src/android/leancloud/avoscloud-statistics-v3.1.4.jar and b/src/android/leancloud/avoscloud-statistics-v3.3.jar differ diff --git a/src/ios/AppDelegate+LeanPush.m b/src/ios/AppDelegate+LeanPush.m index de82cb0..a6f94b9 100644 --- a/src/ios/AppDelegate+LeanPush.m +++ b/src/ios/AppDelegate+LeanPush.m @@ -8,7 +8,7 @@ @implementation AppDelegate (CDVLean) void swizzleMethod(Class c, SEL originalSelector) { NSString *original = NSStringFromSelector(originalSelector); - + SEL swizzledSelector = NSSelectorFromString([@"swizzled_" stringByAppendingString:original]); SEL noopSelector = NSSelectorFromString([@"noop_" stringByAppendingString:original]); @@ -16,12 +16,12 @@ void swizzleMethod(Class c, SEL originalSelector) originalMethod = class_getInstanceMethod(c, originalSelector); swizzledMethod = class_getInstanceMethod(c, swizzledSelector); noop = class_getInstanceMethod(c, noopSelector); - + BOOL didAddMethod = class_addMethod(c, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); - + if (didAddMethod) { class_replaceMethod(c, @@ -40,7 +40,7 @@ + (void)load static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class cls = [self class]; - + swizzleMethod(cls, @selector(application:didFinishLaunchingWithOptions:)); swizzleMethod(cls, @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:)); swizzleMethod(cls, @selector(application:didFailToRegisterForRemoteNotificationsWithError:)); @@ -55,7 +55,7 @@ - (BOOL)swizzled_application:(UIApplication*)application didFinishLaunchingWithO // So, when calling swizzled_application, we are actually calling the original application method // similar with subclass calling super method. Neat! BOOL ret = [self swizzled_application:application didFinishLaunchingWithOptions:launchOptions]; - + if (ret) { // 1. Initialize LeanCloud // 2. Send analysis info @@ -65,7 +65,7 @@ - (BOOL)swizzled_application:(UIApplication*)application didFinishLaunchingWithO if (appId && appKey) { // init [AVOSCloud setApplicationId:appId clientKey:appKey]; - + // analysis if (application.applicationState != UIApplicationStateBackground) { // Track an app open here if we launch with a push, unless @@ -95,7 +95,14 @@ - (BOOL)swizzled_application:(UIApplication*)application didFinishLaunchingWithO NSLog(@"LeanCloud app ID/key not specified"); } } + NSDictionary *localNotif = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"]; + if (localNotif) + { + CDVLeanPush *pushHandler = [self.viewController getCommandInstance:@"LeanPush"]; + [pushHandler sendJson:localNotif statusIs: @""]; + } + return ret; } @@ -150,24 +157,25 @@ -(void)noop_application:(UIApplication *)application didFailToRegisterForRemoteN -(void)swizzled_application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { [self swizzled_application:application didReceiveRemoteNotification:userInfo]; + CDVLeanPush *pushHandler = [self.viewController getCommandInstance:@"LeanPush"]; if (application.applicationState == UIApplicationStateActive) { - // Do nothing + // foreground + [pushHandler sendJson:userInfo statusIs:@"foreground"]; } else { // The application was just brought from the background to the foreground, // so we consider the app as having been "opened by a push notification." + [pushHandler sendJson:userInfo statusIs:@"background"]; [AVAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo]; } - int num=application.applicationIconBadgeNumber; + int num = application.applicationIconBadgeNumber; if(num!=0){ AVInstallation *currentInstallation = [AVInstallation currentInstallation]; [currentInstallation setBadge:0]; [currentInstallation saveEventually]; application.applicationIconBadgeNumber=0; } - - NSLog(@"receiveRemoteNotification"); } -(void)noop_application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo diff --git a/src/ios/CDVLeanPush.h b/src/ios/CDVLeanPush.h index 3794f46..9c2c994 100644 --- a/src/ios/CDVLeanPush.h +++ b/src/ios/CDVLeanPush.h @@ -8,8 +8,16 @@ @property (nonatomic, strong) NSString *leancloudAppId; @property (nonatomic, strong) NSString *leancloudAppKey; +@property (nonatomic, strong) NSString *cacheResult; +@property (nonatomic, strong) NSString *callback; + - (void)subscribe:(CDVInvokedUrlCommand *)command; - (void)unsubscribe:(CDVInvokedUrlCommand *)command; - (void)clearSubscription:(CDVInvokedUrlCommand *)command; +- (void)onNotificationReceived:(CDVInvokedUrlCommand *)command; +- (void)getInstallation:(CDVInvokedUrlCommand *)command; +- (void)getCacheResult:(CDVInvokedUrlCommand *)command; +- (void)sendJson:(NSDictionary *)command statusIs:(NSString *)status; + -@end \ No newline at end of file +@end diff --git a/src/ios/CDVLeanPush.m b/src/ios/CDVLeanPush.m index cf0c0d0..72c3cd9 100644 --- a/src/ios/CDVLeanPush.m +++ b/src/ios/CDVLeanPush.m @@ -56,131 +56,105 @@ - (void)clearSubscription:(CDVInvokedUrlCommand *)command [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } -- (void)onViewStart:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult = nil; - NSString* viewId = [command.arguments objectAtIndex:0]; - - NSLog(@"CDVLeanPush onViewStart %@", viewId); - - if (viewId != nil && [viewId length] > 0) { - [AVAnalytics beginLogPageView:viewId]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)onViewEnd:(CDVInvokedUrlCommand*)command +- (void)getInstallation:(CDVInvokedUrlCommand *)command { - CDVPluginResult* pluginResult = nil; - NSString* viewId = [command.arguments objectAtIndex:0]; + CDVPluginResult* pluginResult = nil; - NSLog(@"CDVLeanPush onViewEnd %@", viewId); + NSLog(@"CDVLeanPush getInstallation"); - if (viewId != nil && [viewId length] > 0) { - [AVAnalytics endLogPageView:viewId]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } + AVInstallation *currentInstallation = [AVInstallation currentInstallation]; + if(currentInstallation != nil && currentInstallation.deviceToken != nil) { + NSLog(@"device token: %@", currentInstallation.deviceToken); + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[NSString stringWithFormat:@"ios,%@", currentInstallation.deviceToken]]; + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Fail to get Installation."]; + } - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } -- (void)event:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult = nil; - NSString* eventId = [command argumentAtIndex:0 withDefault:nil]; - NSString* label = [command argumentAtIndex:1 withDefault:nil]; - NSLog(@"CDVLeanPush event %@ %@", eventId, label); - if (eventId != nil && [eventId length] > 0) { - [AVAnalytics event:eventId label:label]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} - -- (void)onEventStart:(CDVInvokedUrlCommand*)command +- (void)onNotificationReceived:(CDVInvokedUrlCommand *)command { - CDVPluginResult* pluginResult = nil; - NSString* eventId = [command argumentAtIndex:0 withDefault:nil]; - NSString* label = [command argumentAtIndex:1 withDefault:nil]; + self.callback = [command.arguments objectAtIndex:0]; +// NSMutableDictionary* options = [command.arguments objectAtIndex:0]; +// self.callback = [options objectForKey:@"ecb"]; + CDVPluginResult *commandResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"onMessage Success"]; + [self.commandDelegate sendPluginResult:commandResult callbackId:command.callbackId]; +} - NSLog(@"CDVLeanPush onEventStart %@ %@", eventId, label); - if (eventId != nil && [eventId length] > 0) { - [AVAnalytics beginEvent:eventId label:label]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; +-(void)parseDictionary:(NSDictionary *)inDictionary intoJSON:(NSMutableString *)jsonString +{ + NSArray *keys = [inDictionary allKeys]; + NSString *key; + + for (key in keys) + { + id thisObject = [inDictionary objectForKey:key]; + + if ([thisObject isKindOfClass:[NSDictionary class]]) + [self parseDictionary:thisObject intoJSON:jsonString]; + else if ([thisObject isKindOfClass:[NSString class]]) + [jsonString appendFormat:@"\"%@\":\"%@\",", + key, + [[[[inDictionary objectForKey:key] + stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"] + stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""] + stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]]; + else { + [jsonString appendFormat:@"\"%@\":\"%@\",", key, [inDictionary objectForKey:key]]; + } } - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } -- (void)onEventEnd:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult = nil; - NSString* eventId = [command argumentAtIndex:0 withDefault:nil]; - NSString* label = [command argumentAtIndex:1 withDefault:nil]; - NSLog(@"CDVLeanPush onEventEnd %@ %@", eventId, label); - - if (eventId != nil && [eventId length] > 0) { - [AVAnalytics endEvent:eventId label:label]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; +- (NSString *)toJsonString:(NSDictionary *)dict; +{ + NSMutableString *jsonStr = [NSMutableString stringWithString:@"{"]; + [self parseDictionary:dict intoJSON:jsonStr]; + [jsonStr appendString:@"}"]; + return jsonStr; } -- (void)onKVEventStart:(CDVInvokedUrlCommand*)command +- (void) sendJson:(NSDictionary *)command statusIs:(NSString *)status { - CDVPluginResult* pluginResult = nil; - NSString* eventId = [command argumentAtIndex:0 withDefault:nil]; - NSString* keyName = [command argumentAtIndex:1 withDefault:nil]; - NSString* attr = [command argumentAtIndex:2 withDefault:nil]; - NSString* value = [command argumentAtIndex:3 withDefault:nil]; - - NSLog(@"CDVLeanPush onKVEventStart %@ %@ {%@:%@}", eventId, keyName, attr, value); - - if (eventId != nil && [eventId length] > 0) { - NSDictionary *attrs = [NSDictionary dictionaryWithObject:value forKey:attr]; - [AVAnalytics beginEvent:eventId primarykey:keyName attributes:attrs]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; + NSMutableString *jsonStr = [NSMutableString stringWithString:@"{"]; + [self parseDictionary:command intoJSON:jsonStr]; + if ([jsonStr length] > 0) { + jsonStr = [NSMutableString stringWithString:[jsonStr substringToIndex:[jsonStr length] - 1]]; + } + [jsonStr appendString:@"}"]; + +// NSString * jsonStr = [NSString stringWithFormat:@"%@", command]; + + if (self.callback) { + NSString * jsCallBack = [NSString stringWithFormat:@"%@(%@,'%@');", self.callback,jsonStr,status]; +// NSLog(jsCallBack) ; + // [self.webView stringByEvaluatingJavaScriptFromString:jsCallBack]; + if ([self.webView respondsToSelector:@selector(stringByEvaluatingJavaScriptFromString:)]) { + // Cordova-iOS pre-4 + [self.webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:jsCallBack waitUntilDone:NO]; + } else { + // Cordova-iOS 4+ + [self.webView performSelectorOnMainThread:@selector(evaluateJavaScript:completionHandler:) withObject:jsCallBack waitUntilDone:NO]; + } + }else{ + self.cacheResult = jsonStr; } - - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } -- (void)onKVEventEnd:(CDVInvokedUrlCommand*)command +- (void) getCacheResult:(CDVInvokedUrlCommand *)command { CDVPluginResult* pluginResult = nil; - NSString* eventId = [command argumentAtIndex:0 withDefault:nil]; - NSString* keyName = [command argumentAtIndex:1 withDefault:nil]; - - NSLog(@"CDVLeanPush onKVEventEnd %@ %@", eventId, keyName); - - if (eventId != nil && [eventId length] > 0) { - [AVAnalytics endEvent:eventId primarykey:keyName]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } + NSLog(@"CDVLeanPush getCacheResult = %@", self.cacheResult); + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:self.cacheResult]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} + self.cacheResult = NULL; +} @end diff --git a/src/ios/Frameworks/AVOSCloud.framework/AVOSCloud b/src/ios/Frameworks/AVOSCloud.framework/AVOSCloud index 4662080..2a14fc5 100644 Binary files a/src/ios/Frameworks/AVOSCloud.framework/AVOSCloud and b/src/ios/Frameworks/AVOSCloud.framework/AVOSCloud differ diff --git a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVAnalytics.h b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVAnalytics.h index 69959c9..6f5e2b7 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVAnalytics.h +++ b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVAnalytics.h @@ -70,42 +70,42 @@ typedef NS_ENUM(int, AVReportPolicy){ + (void)setAnalyticsEnabled:(BOOL)value; -/** 开启CrashReport收集, 默认是开启状态. +/** 开启CrashReport收集, 默认是关闭状态. - @param value 设置成NO,就可以关闭CrashReport收集. + @param value 设置成 YES,就可以开启CrashReport收集. @return void. */ -+ (void)setCrashReportEnabled:(BOOL)value; ++ (void)setCrashReportEnabled:(BOOL)value AVDeprecated("使用 AVOSCloudCrashReporting.framework"); -/** 开启CrashReport收集, 默认是开启状态. +/** 开启CrashReport收集, 默认是关闭状态. - @param value 设置成NO,就可以关闭CrashReport收集. + @param value 设置成 YES,就可以开启CrashReport收集. @param completion 设置完成后回调. @return void. */ -+ (void)setCrashReportEnabled:(BOOL)value completion:(void (^)(void))completion; ++ (void)setCrashReportEnabled:(BOOL)value completion:(void (^)(void))completion AVDeprecated("使用 AVOSCloudCrashReporting.framework"); /** 开启CrashReport收集, 并且尝试忽略异常. @discuss 当异常被捕获后,如果开启了CrashReport功能,异常会被自动捕获,如果开启ignore,会尝试阻止app崩溃, 如果阻止成功,则会提示(UIAlertView)用户程序可能不稳定,请用户选择继续运行还是退出. @warning 这不是解决问题的办法,因为App仍然存在不可控因素,而且忽略异常后会造成CPU的占用率提高5%左右. 所以,请尽量找出引起Crash的原因(AVOSCloud后台的错误报告中已经记录了相关信息),并且修复这个问题. - @param value 设置成NO,就可以关闭CrashReport收集. + @param value 设置成YES,就可以开启CrashReport收集. @param ignore 设置成YES,可以尝试忽略异常. */ -+ (void)setCrashReportEnabled:(BOOL)value andIgnore:(BOOL)ignore; ++ (void)setCrashReportEnabled:(BOOL)value andIgnore:(BOOL)ignore AVDeprecated("使用 AVOSCloudCrashReporting.framework"); /** 开启CrashReport收集, 并且尝试忽略异常. @discuss 效果等同于`setCrashReportEnabled:andIgnore:` 但是可以自定义弹出提醒的文字内容. - @param value 设置成NO,就可以关闭CrashReport收集. + @param value 设置成 YES,就可以开启 CrashReport 收集. @param alertTitle 弹出提醒的标题 @param alertMsg 弹出提醒的内容 @param alertQuit `退出`按钮的文字 @param alertContinue `继续`按钮的文字 */ -+ (void)setCrashReportEnabled:(BOOL)value withIgnoreAlertTitle:(NSString*)alertTitle andMessage:(NSString*)alertMsg andQuitTitle:(NSString*)alertQuit andContinueTitle:(NSString*)alertContinue; ++ (void)setCrashReportEnabled:(BOOL)value withIgnoreAlertTitle:(NSString*)alertTitle andMessage:(NSString*)alertMsg andQuitTitle:(NSString*)alertQuit andContinueTitle:(NSString*)alertContinue AVDeprecated("使用 AVOSCloudCrashReporting.framework"); /** 设置是否打印sdk的log信息,默认不开启 diff --git a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVConstants.h b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVConstants.h index 3d7d7cc..9f7e78a 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVConstants.h +++ b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVConstants.h @@ -63,14 +63,6 @@ typedef NS_ENUM(int, AVCachePolicy){ kAVCachePolicyCacheThenNetwork, } ; -typedef AVCachePolicy PFCachePolicy; -#define kPFCachePolicyIgnoreCache kAVCachePolicyIgnoreCache -#define kPFCachePolicyCacheOnly kAVCachePolicyCacheOnly -#define kPFCachePolicyNetworkOnly kAVCachePolicyNetworkOnly -#define kPFCachePolicyCacheElseNetwork kAVCachePolicyCacheElseNetwork -#define kPFCachePolicyNetworkElseCache kAVCachePolicyNetworkElseCache -#define kPFCachePolicyCacheThenNetwork kAVCachePolicyCacheThenNetwork - // Errors @@ -183,98 +175,19 @@ extern NSInteger const kAVErrorFacebookInvalidSession; /*! @abstract 251: Invalid linked session */ extern NSInteger const kAVErrorInvalidLinkedSession; - - - - -#define kPFErrorInternalServer kAVErrorInternalServer -#define kPFErrorConnectionFailed kAVErrorConnectionFailed -#define kPFErrorObjectNotFound kAVErrorObjectNotFound -#define kPFErrorInvalidQuery kAVErrorInvalidQuery -#define kPFErrorInvalidClassName kAVErrorInvalidClassName -#define kPFErrorMissingObjectId kAVErrorMissingObjectId -#define kPFErrorInvalidKeyName kAVErrorInvalidKeyName -#define kPFErrorInvalidPointer kAVErrorInvalidPointer -#define kPFErrorInvalidJSON kAVErrorInvalidJSON -#define kPFErrorCommandUnavailable kAVErrorCommandUnavailable -#define kPFErrorIncorrectType kAVErrorIncorrectType -#define kPFErrorInvalidChannelName kAVErrorInvalidChannelName -#define kPFErrorInvalidDeviceToken kAVErrorInvalidDeviceToken -#define kPFErrorPushMisconfigured kAVErrorPushMisconfigured -#define kPFErrorObjectTooLarge kAVErrorObjectTooLarge -#define kPFErrorOperationForbidden kAVErrorOperationForbidden -#define kPFErrorCacheMiss kAVErrorCacheMiss -#define kPFErrorInvalidNestedKey kAVErrorInvalidNestedKey -#define kPFErrorInvalidFileName kAVErrorInvalidFileName -#define kPFErrorInvalidACL kAVErrorInvalidACL -#define kPFErrorTimeout kAVErrorTimeout -#define kPFErrorInvalidEmailAddress kAVErrorInvalidEmailAddress -#define kPFErrorDuplicateValue kAVErrorDuplicateValue -#define kPFErrorInvalidRoleName kAVErrorInvalidRoleName -#define kPFErrorExceededQuota kAVErrorExceededQuota -#define kPFScriptError kAVScriptError -#define kPFValidationError kAVValidationError -#define kPFErrorReceiptMissing kAVErrorReceiptMissing -#define kPFErrorInvalidPurchaseReceipt kAVErrorInvalidPurchaseReceipt -#define kPFErrorPaymentDisabled kAVErrorPaymentDisabled -#define kPFErrorInvalidProductIdentifier kAVErrorInvalidProductIdentifier -#define kPFErrorProductNotFoundInAppStore kAVErrorProductNotFoundInAppStore -#define kPFErrorInvalidServerResponse kAVErrorInvalidServerResponse -#define kPFErrorProductDownloadFileSystemFailure kAVErrorProductDownloadFileSystemFailure -#define kPFErrorInvalidImageData kAVErrorInvalidImageData -#define kPFErrorUnsavedFile kAVErrorUnsavedFile -#define kPFErrorFileDeleteFailure kAVErrorFileDeleteFailure -#define kPFErrorUsernameMissing kAVErrorUsernameMissing -#define kPFErrorUserPasswordMissing kAVErrorUserPasswordMissing -#define kPFErrorUsernameTaken kAVErrorUsernameTaken -#define kPFErrorUserEmailTaken kAVErrorUserEmailTaken -#define kPFErrorUserEmailMissing kAVErrorUserEmailMissing -#define kPFErrorUserWithEmailNotFound kAVErrorUserWithEmailNotFound -#define kPFErrorUserCannotBeAlteredWithoutSession kAVErrorUserCannotBeAlteredWithoutSession -#define kPFErrorUserCanOnlyBeCreatedThroughSignUp kAVErrorUserCanOnlyBeCreatedThroughSignUp -#define kPFErrorFacebookAccountAlreadyLinked kAVErrorFacebookAccountAlreadyLinked -#define kPFErrorAccountAlreadyLinked kAVErrorAccountAlreadyLinked -#define kPFErrorUserIdMismatch kAVErrorUserIdMismatch -#define kPFErrorUsernamePasswordMismatch kAVErrorUsernamePasswordMismatch -#define kPFErrorUserNotFound kAVErrorUserNotFound -#define kPFErrorFacebookIdMissing kAVErrorFacebookIdMissing -#define kPFErrorLinkedIdMissing kAVErrorLinkedIdMissing -#define kPFErrorFacebookInvalidSession kAVErrorFacebookInvalidSession -#define kPFErrorInvalidLinkedSession kAVErrorInvalidLinkedSession - -#define kPFErrorInvalidMobilePhoneNumber kAVErrorInvalidMobilePhoneNumber -#define kPFErrorUserMobilePhoneMissing kAVErrorUserMobilePhoneMissing -#define kPFErrorUserWithMobilePhoneNotFound kAVErrorUserWithMobilePhoneNotFound -#define kPFErrorUserMobilePhoneNumberTaken kAVErrorUserMobilePhoneNumberTaken -#define kPFErrorUserMobilePhoneNotVerified kAVErrorUserMobilePhoneNotVerified - -typedef void (^PFBooleanResultBlock)(BOOL succeeded, NSError *error); -typedef void (^PFIntegerResultBlock)(NSInteger number, NSError *error); -typedef void (^PFArrayResultBlock)(NSArray *objects, NSError *error); -typedef void (^PFObjectResultBlock)(AVObject *object, NSError *error); -typedef void (^PFSetResultBlock)(NSSet *channels, NSError *error); -typedef void (^PFUserResultBlock)(AVUser *user, NSError *error); -typedef void (^PFDataResultBlock)(NSData *data, NSError *error); -typedef void (^PFImageResultBlock)(UIImage * image, NSError *error); -typedef void (^PFDataStreamResultBlock)(NSInputStream *stream, NSError *error); -typedef void (^PFStringResultBlock)(NSString *string, NSError *error); -typedef void (^PFIdResultBlock)(id object, NSError *error); -typedef void (^PFProgressBlock)(NSInteger percentDone); -typedef void (^PFFileResultBlock)(AVFile * file, NSError *error); +typedef void (^AVBooleanResultBlock)(BOOL succeeded, NSError *error); +typedef void (^AVIntegerResultBlock)(NSInteger number, NSError *error); +typedef void (^AVArrayResultBlock)(NSArray *objects, NSError *error); +typedef void (^AVObjectResultBlock)(AVObject *object, NSError *error); +typedef void (^AVSetResultBlock)(NSSet *channels, NSError *error); +typedef void (^AVUserResultBlock)(AVUser *user, NSError *error); +typedef void (^AVDataResultBlock)(NSData *data, NSError *error); +typedef void (^AVImageResultBlock)(UIImage * image, NSError *error); +typedef void (^AVDataStreamResultBlock)(NSInputStream *stream, NSError *error); +typedef void (^AVStringResultBlock)(NSString *string, NSError *error); +typedef void (^AVIdResultBlock)(id object, NSError *error); +typedef void (^AVProgressBlock)(NSInteger percentDone); +typedef void (^AVFileResultBlock)(AVFile * file, NSError *error); typedef void (^AVDictionaryResultBlock)(NSDictionary * dict, NSError *error); -typedef PFBooleanResultBlock AVBooleanResultBlock; -typedef PFIntegerResultBlock AVIntegerResultBlock; -typedef PFArrayResultBlock AVArrayResultBlock; -typedef PFObjectResultBlock AVObjectResultBlock; -typedef PFSetResultBlock AVSetResultBlock; -typedef PFUserResultBlock AVUserResultBlock; -typedef PFDataResultBlock AVDataResultBlock; -typedef PFImageResultBlock AVImageResultBlock; -typedef PFDataStreamResultBlock AVDataStreamResultBlock; -typedef PFStringResultBlock AVStringResultBlock; -typedef PFIdResultBlock AVIdResultBlock; -typedef PFProgressBlock AVProgressBlock; -typedef PFFileResultBlock AVFileResultBlock; - #define AVDeprecated(explain) __attribute__((deprecated(explain))) diff --git a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVFile.h b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVFile.h index dda9d15..e3c6d01 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVFile.h +++ b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVFile.h @@ -225,6 +225,33 @@ The name of the file. + (void)getFileWithObjectId:(NSString *)objectId withBlock:(AVFileResultBlock)block; +/*! + Get a thumbnail URL for image saved on Qiniu. + + @param scaleToFit Scale the thumbnail and keep aspect ratio. + @param width The thumbnail width. + @param height The thumbnail height. + @param quality The thumbnail image quality in 1 - 100. + @param format The thumbnail image format such as 'jpg', 'gif', 'png', 'tif' etc. + */ +- (NSString *)getThumbnailURLWithScaleToFit:(BOOL)scaleToFit + width:(int)width + height:(int)height + quality:(int)quality + format:(NSString *)format; + +/*! + Get a thumbnail URL for image saved on Qiniu. + @see -getThumbnailURLWithScaleToFit:width:height:quality:format + + @param scaleToFit Scale the thumbnail and keep aspect ratio. + @param width The thumbnail width. + @param height The thumbnail height. + */ +- (NSString *)getThumbnailURLWithScaleToFit:(BOOL)scaleToFit + width:(int)width + height:(int)height; + /*! Gets a thumbnail asynchronously and calls the given block with the result. diff --git a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVInstallation.h b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVInstallation.h index 48c82e1..eb0d2bf 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVInstallation.h +++ b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVInstallation.h @@ -70,6 +70,9 @@ /// The device token for the AVInstallation. @property (nonatomic, retain) NSString *deviceToken; +/// The device profile for the AVInstallation. +@property (nonatomic, retain) NSString *deviceProfile; + /// The badge for the AVInstallation. @property (nonatomic, assign) NSInteger badge; diff --git a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVOSCloud.h b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVOSCloud.h index b09c201..7685bc7 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVOSCloud.h +++ b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVOSCloud.h @@ -67,6 +67,11 @@ typedef enum AVLogLevel : NSUInteger { */ @interface AVOSCloud : NSObject +/*! + * Enable logs of all levels and domains. + */ ++ (void)setAllLogsEnabled:(BOOL)enabled; + /** * 设置SDK信息显示 * @param verbosePolicy SDK信息显示策略,kAVVerboseShow为显示, @@ -148,6 +153,14 @@ typedef enum AVLogLevel : NSUInteger { #pragma mark Schedule work +/** + * Register remote notification with types. + * @param types Notification types. + * @param categories A set of UIUserNotificationCategory objects that define the groups of actions a notification may include. + * NOTE: categories only supported by iOS 8 and later. If application run below iOS 8, categories will be ignored. + */ ++ (void)registerForRemoteNotificationTypes:(NSUInteger)types categories:(NSSet *)categories; + /** * get the query cache expired days * @@ -213,6 +226,17 @@ typedef enum AVLogLevel : NSUInteger { variables:(NSDictionary *)variables callback:(AVBooleanResultBlock)callback; +/*! + * 请求语音短信验证码,需要开启手机短信验证 API 选项 + * 发送语音短信到指定手机上 + * @param phoneNumber 11 位电话号码 + * @param IDD 号码的所在地国家代码,如果传 nil,默认为 "+86" + * @param callback 回调结果 + */ ++(void)requestVoiceCodeWithPhoneNumber:(NSString *)phoneNumber + IDD:(NSString *)IDD + callback:(AVBooleanResultBlock)callback; + /*! * 验证短信验证码,需要开启手机短信验证 API 选项。 * 发送验证码给服务器进行验证。 @@ -222,24 +246,4 @@ typedef enum AVLogLevel : NSUInteger { */ +(void)verifySmsCode:(NSString *)code mobilePhoneNumber:(NSString *)phoneNumber callback:(AVBooleanResultBlock)callback; - -typedef AVUser PFUser; -typedef AVObject PFObject; -typedef AVGeoPoint PFGeoPoint; -typedef AVQuery PFQuery; -typedef AVFile PFFile; -typedef AVAnonymousUtils PFAnonymousUtils; -typedef AVACL PFACL; -typedef AVRole PFRole; -typedef AVInstallation PFInstallation; -typedef AVPush PFPush; -typedef AVOSCloud Parse; -typedef AVCloud PFCloud; - -typedef AVRelation PFRelation; - -#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -typedef AVAnalytics PFAnalytics; -#endif - @end diff --git a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVUser.h b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVUser.h index ce2a20c..4f5db36 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/Headers/AVUser.h +++ b/src/ios/Frameworks/AVOSCloud.framework/Headers/AVUser.h @@ -28,6 +28,15 @@ A AVOS Cloud Framework User Object that is a local representation of a user pers */ + (instancetype)currentUser; +/*! + * change the current login user manually. + * @param newUser 新的 AVUser 实例 + * @param save 是否需要把 newUser 保存到本地缓存。如果 newUser==nil && save==YES,则会清除本地缓存 + * Note: 请注意不要随意调用这个函数! + */ ++(void)changeCurrentUser:(AVUser *)newUser + save:(BOOL)save; + /// The session token for the AVUser. This is set by the server upon successful authentication. @property (nonatomic, retain) NSString *sessionToken; diff --git a/src/ios/Frameworks/AVOSCloud.framework/Info.plist b/src/ios/Frameworks/AVOSCloud.framework/Info.plist index a1d7a8e..1d7686d 100644 Binary files a/src/ios/Frameworks/AVOSCloud.framework/Info.plist and b/src/ios/Frameworks/AVOSCloud.framework/Info.plist differ diff --git a/src/ios/Frameworks/AVOSCloud.framework/PrivateHeaders/AVGlobal.h b/src/ios/Frameworks/AVOSCloud.framework/PrivateHeaders/AVGlobal.h index e05643e..dfb432d 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/PrivateHeaders/AVGlobal.h +++ b/src/ios/Frameworks/AVOSCloud.framework/PrivateHeaders/AVGlobal.h @@ -13,6 +13,7 @@ #define channelsTag @"channels" #define badgeTag @"badge" #define deviceTokenTag @"deviceToken" +#define deviceProfileTag @"deviceProfile" #define timeZoneTag @"timezone" #define usernameTag @"username" #define passwordTag @"password" @@ -22,6 +23,7 @@ #define smsCodeTag @"smsCode" #define deviceTypeTag @"deviceType" #define installationIdTag @"installationId" +#define authDataTag @"authData" #define enableTag @"enable" diff --git a/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeDirectory b/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeDirectory index 63d27b4..02ac97c 100644 Binary files a/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeDirectory and b/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeDirectory differ diff --git a/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeResources b/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeResources index 928a711..7c51a23 100644 --- a/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeResources +++ b/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeResources @@ -34,7 +34,7 @@ Headers/AVAnalytics.h - fV++MFbI1qyE7AW2AklIiGAB09Q= + HzOKpGsqaqsPXS2rWGmvdHXAQvQ= Headers/AVAnonymousUtils.h @@ -50,11 +50,11 @@ Headers/AVConstants.h - ScgWmrZ/2h3ZEms3v43xIUVc5QI= + 7xPo7MgrjFylR0dHGnaB+YuwsR8= Headers/AVFile.h - 2OOA6h7tqZKUZ0kliZx8Z+7n+Ss= + qCoVzELEcA4EfD6Hb2e4beJ8yD8= Headers/AVGeoPoint.h @@ -74,7 +74,7 @@ Headers/AVInstallation.h - CNjepoCdfCL+kkOyty2bKqRCFk8= + KsGK66WmbdXGbKPbvmN403RClPI= Headers/AVLogger.h @@ -86,7 +86,7 @@ Headers/AVOSCloud.h - T+gMj5MUkx53Ov3YRpKP2xExFSs= + pBOnnWH/TuR/HioMJlZkaonUpy8= Headers/AVObject+Subclass.h @@ -138,7 +138,7 @@ Headers/AVUser.h - atHiEFqQbYIzfUwUrgFTazXfdzs= + r42Zbjm89U+ltucInhAhiGeom2A= Headers/AVUserFeedback.h @@ -154,7 +154,7 @@ Info.plist - wMMAqMkB0OgFC41H4b03MU+o4FA= + B9JPdCn48ppiCdII+AQsqESdhAk= Modules/module.modulemap @@ -174,7 +174,7 @@ PrivateHeaders/AVGlobal.h - LWLMV2uiMQLJucFIg06OMtIUi1s= + aAl+H3D3dLX/4sxSXI4BOv5F1QY= PrivateHeaders/AVHTTPClient.h @@ -253,7 +253,7 @@ Headers/AVAnalytics.h - fV++MFbI1qyE7AW2AklIiGAB09Q= + HzOKpGsqaqsPXS2rWGmvdHXAQvQ= Headers/AVAnonymousUtils.h @@ -269,11 +269,11 @@ Headers/AVConstants.h - ScgWmrZ/2h3ZEms3v43xIUVc5QI= + 7xPo7MgrjFylR0dHGnaB+YuwsR8= Headers/AVFile.h - 2OOA6h7tqZKUZ0kliZx8Z+7n+Ss= + qCoVzELEcA4EfD6Hb2e4beJ8yD8= Headers/AVGeoPoint.h @@ -293,7 +293,7 @@ Headers/AVInstallation.h - CNjepoCdfCL+kkOyty2bKqRCFk8= + KsGK66WmbdXGbKPbvmN403RClPI= Headers/AVLogger.h @@ -305,7 +305,7 @@ Headers/AVOSCloud.h - T+gMj5MUkx53Ov3YRpKP2xExFSs= + pBOnnWH/TuR/HioMJlZkaonUpy8= Headers/AVObject+Subclass.h @@ -357,7 +357,7 @@ Headers/AVUser.h - atHiEFqQbYIzfUwUrgFTazXfdzs= + r42Zbjm89U+ltucInhAhiGeom2A= Headers/AVUserFeedback.h @@ -389,7 +389,7 @@ PrivateHeaders/AVGlobal.h - LWLMV2uiMQLJucFIg06OMtIUi1s= + aAl+H3D3dLX/4sxSXI4BOv5F1QY= PrivateHeaders/AVHTTPClient.h diff --git a/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeSignature b/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeSignature index bc3746a..f941144 100644 Binary files a/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeSignature and b/src/ios/Frameworks/AVOSCloud.framework/_CodeSignature/CodeSignature differ diff --git a/src/ios/Frameworks/libsqlite3.dylib b/src/ios/Frameworks/libsqlite3.dylib new file mode 100755 index 0000000..4705da5 Binary files /dev/null and b/src/ios/Frameworks/libsqlite3.dylib differ diff --git a/www/.tern-port b/www/.tern-port new file mode 100644 index 0000000..b5d028f --- /dev/null +++ b/www/.tern-port @@ -0,0 +1 @@ +55222 \ No newline at end of file diff --git a/www/LeanPush.js b/www/LeanPush.js index 9f58ef3..1962a4b 100644 --- a/www/LeanPush.js +++ b/www/LeanPush.js @@ -1,18 +1,67 @@ var exec = require('cordova/exec'); module.exports = { - subscribe: function(channel, success, error) { - console.log('subscribe', channel); - exec(success, error, "LeanPush", "subscribe", [channel]); - }, + getInstallation: function(success, error) { + console.log('getInstallation'); + exec(function(info) { + var a = info.split(','); + success({ + 'deviceType': a[0], + installationId: a[1], + 'deviceToken': a[1] + }); + }, error, "LeanPush", "getInstallation", []); + }, + subscribe: function(channel, success, error) { + console.log('subscribe', channel); + exec(success, error, "LeanPush", "subscribe", [channel]); + }, - unsubscribe: function(channel, success, error) { - console.log('unsubscribe', channel); - exec(success, error, "LeanPush", "unsubscribe", [channel]); - }, + unsubscribe: function(channel, success, error) { + console.log('unsubscribe', channel); + exec(success, error, "LeanPush", "unsubscribe", [channel]); + }, - clearSubscription: function(success, error) { - console.log('clearSubscription'); - exec(success, error, "LeanPush", "clearSubscription", []); - } + clearSubscription: function(success, error) { + console.log('clearSubscription'); + exec(success, error, "LeanPush", "clearSubscription", []); + }, + init: function(fun) { + console.log('LeanPush Initialization'); + window.LeanPush.onNotificationReceived(fun || function(notice) {}); + + window.LeanPush.init.__cb = function(x, status) { + var notice; + try { + + if (typeof x == 'string') { + notice = JSON.parse(x) || {}; + } else { + notice = x; + } + } catch (e) { + notice = notice || {}; + notice.error = e; + } + if (notice) { + notice.prevAppState = status || 'closed'; + console.log('leancloud:notificationReceived', JSON.stringify(notice)); + if (typeof angular != 'undefined') { + var $body = angular.element(document.body); + $body.scope().$root.$emit('leancloud:notificationReceived', + notice); + } + window.LeanPush.onNotificationReceived._fun(notice); + } + }; + cordova.exec(window.LeanPush.init.__cb, null, "LeanPush", + "getCacheResult", []); + cordova.exec(null, null, "LeanPush", "onNotificationReceived", [ + 'window.LeanPush.init.__cb' + ]); + + }, + onNotificationReceived: function(f) { + window.LeanPush.onNotificationReceived._fun = f; + } };