com.avos.avoscloud.AVPush Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-sdk Show documentation
Show all versions of java-sdk Show documentation
LeanCloud Storage, Engine, SMS SDK
package com.avos.avoscloud;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.avos.avoscloud.internal.InternalConfigurationController;
/**
*
* The AVPush is a local representation of data that can be sent as a push notification.
*
*
* The typical workflow for sending a push notification from the client is to construct a new
* AVPush, use the setter functions to fill it with data, and then use AVPush.sendInBackground() to
* send it.
*
*/
public class AVPush {
private static final String INSTALLATIONTAG = "_Installation";
private static final String deviceTypeTag = "deviceType";
private static final Set DEVICE_TYPES = new HashSet();
static {
DEVICE_TYPES.add("android");
DEVICE_TYPES.add("ios");
}
private final Set channelSet;
private com.avos.avoscloud.AVQuery extends AVObject> pushQuery;
private String cql;
private long expirationTime;
private long expirationTimeInterval;
private final Set pushTarget;
private final Map pushData;
private volatile AVObject notification;
private Date pushDate = null;
private boolean production = true;
static {
AVPowerfulUtils.createSettings(AVPush.class.getSimpleName(), "push", "");
}
/**
* Creates a new push notification. The default channel is the empty string, also known as the
* global broadcast channel, but this value can be overridden using AVPush.setChannel(String),
* AVPush.setChannels(Collection) or AVPush.setQuery(AVQuery). Before sending the push
* notification you must call either AVPush.setMessage(String) or AVPush.setData(JSONObject).
*/
public AVPush() {
channelSet = new HashSet();
pushData = new HashMap();
pushTarget = new HashSet(DEVICE_TYPES);
pushQuery = new AVQuery(INSTALLATIONTAG);
}
public Set getChannelSet() {
return channelSet;
}
/**
* 返回推送后创建的_Notification对象。
*
* @return _Notification对象
*/
public AVObject getNotification() {
return notification;
}
public AVQuery getPushQuery() {
return pushQuery;
}
public Date getPushDate() {
return pushDate;
}
public long getExpirationTime() {
return expirationTime;
}
public long getExpirationTimeInterval() {
return expirationTimeInterval;
}
public Set getPushTarget() {
return pushTarget;
}
public Map getPushData() {
return pushData;
}
/**
* Clears both expiration values, indicating that the notification should never expire.
*/
public void clearExpiration() {
expirationTime = 0L;
expirationTimeInterval = 0L;
}
/**
* Sends this push notification while blocking this thread until the push notification has
* successfully reached the AVOSCloud servers. Typically, you should use AVPush.sendInBackground()
* instead of this, unless you are managing your own threading.
*/
public void send() {
sendInBackground(true, null);
}
/**
* A helper method to concisely send a push to a query. This method is equivalent to
*
*
* AVPush push = new AVPush();
* push.setData(data);
* push.setQuery(query);
* push.sendInBackground();
*
*
* @param data The entire data of the push message. See the push guide for more details on the
* data format.
* @param query A AVInstallation query which specifies the recipients of a push.
* @throws AVException if query is not valid
*/
static void sendDataInBackground(JSONObject data, AVQuery extends AVObject> query)
throws AVException {
if (!query.getClassName().equals(INSTALLATIONTAG)) {
throw new AVException(AVException.OTHER_CAUSE, "only installation query is valid");
}
AVPush push = new AVPush();
push.setData(data);
push.setQuery(query);
push.sendInBackground();
}
/**
* A helper method to concisely send a push to a query. This method is equivalent to
*
*
* AVPush push = new AVPush();
* push.setData(data);
* push.setQuery(query);
* push.sendInBackground(callback);
*
*
* @param data The entire data of the push message. See the push guide for more details on the
* data format.
* @param query A AVInstallation query which specifies the recipients of a push.
* @param callback callback.done(e) is called when the send completes.
*/
public static void sendDataInBackground(JSONObject data, AVQuery extends AVObject> query,
SendCallback callback) {
if (!query.getClassName().equals(INSTALLATIONTAG)) {
if (callback != null) {
callback.done(new AVException(AVException.OTHER_CAUSE, "only installation query is valid"));
}
}
AVPush push = new AVPush();
push.setData(data);
push.setQuery(query);
push.sendInBackground(false, callback);
}
/**
* Sends this push notification in a background thread. This is preferable to using send(), unless
* your code is already running from a background thread.
*/
public void sendInBackground() {
sendInBackground(false, null);
}
/**
* Sends this push notification in a background thread. This is preferable to using send(), unless
* your code is already running from a background thread.
*
* @param callback callback.done(e) is called when the send completes.
*/
public void sendInBackground(SendCallback callback) {
sendInBackground(false, callback);
}
private Map pushChannelsData() {
return AVUtils.createStringObjectMap("channels", channelSet);
}
private Map postDataMap() throws AVException {
Map map = new HashMap();
if (pushQuery != null) {
if (pushTarget.size() == 0) {
pushQuery.whereNotContainedIn(deviceTypeTag, DEVICE_TYPES);
} else if (pushTarget.size() == 1) {
pushQuery.whereEqualTo(deviceTypeTag, pushTarget.toArray()[0]);
}
Map pushParameters = pushQuery.assembleParameters();
if (pushParameters.keySet().size() > 0 && !AVUtils.isBlankString(cql)) {
throw new IllegalStateException("You can't use AVQuery and Cloud query at the same time.");
}
for (String k : pushParameters.keySet()) {
map.put(k, JSON.parse(pushParameters.get(k)));
}
}
if (!AVUtils.isBlankString(cql)) {
map.put("cql", cql);
}
if (channelSet.size() > 0) {
map.putAll(pushChannelsData());
}
if (this.expirationTime > 0) {
map.put("expiration_time", this.expirationDateTime());
}
if (this.expirationTimeInterval > 0) {
map.put("push_time", AVUtils.stringFromDate(new Date()));
map.put("expiration_interval", new Long(this.expirationTimeInterval));
}
if (this.pushDate != null) {
map.put("push_time", AVUtils.stringFromDate(pushDate));
}
if (!production) {
map.put("prod", "dev");
}
map.putAll(pushData);
return map;
}
/**
* Sends this push notification in a background thread. This is preferable to using send(), unless
* your code is already running from a background thread.
*
* @param callback callback.done(e) is called when the send completes.
*/
private void sendInBackground(boolean sync, SendCallback callback) {
final SendCallback internalCallback = callback;
String path = "push";
try {
Map map = postDataMap();
String jsonString = AVUtils.jsonStringFromMapWithNull(map);
PaasClient.storageInstance().postObject(path, jsonString, sync, new GenericObjectCallback() {
@Override
public void onSuccess(String content, AVException e) {
notification = new AVObject("_Notification");
AVUtils.copyPropertiesFromJsonStringToAVObject(content, notification);
if (internalCallback != null) {
internalCallback.internalDone(null);
}
}
@Override
public void onFailure(Throwable error, String content) {
if (internalCallback != null) {
internalCallback.internalDone(AVErrorUtils.createException(error, content));
}
}
});
} catch (AVException e) {
if (callback != null) {
callback.internalDone(e);
} else {
LogUtil.log.e("AVPush sent exception", e);
}
}
}
/**
* A helper method to concisely send a push message to a query. This method is equivalent to
*
*
* AVPush push = new AVPush();
* push.setMessage(message);
* push.setQuery(query);
* push.sendInBackground();
*
*
* @param message The message that will be shown in the notification.
* @param query A AVInstallation query which specifies the recipients of a push.
*/
public static void sendMessageInBackground(String message, AVQuery extends AVObject> query) {
if (!query.getClassName().equals(INSTALLATIONTAG)) {
InternalConfigurationController.globalInstance().getInternalLogger()
.e(AVPush.class.getSimpleName(), "only installation query is valid");
return;
}
AVPush push = new AVPush();
push.setMessage(message);
push.setQuery(query);
push.sendInBackground(false, null);
}
/**
* A helper method to concisely send a push message to a query. This method is equivalent to
*
*
* AVPush push = new AVPush();
* push.setMessage(message);
* push.setQuery(query);
* push.sendInBackground(callback);
*
*
* @param message The message that will be shown in the notification.
* @param query A AVInstallation query which specifies the recipients of a push.
* @param callback callback.done(e) is called when the send completes.
*/
public static void sendMessageInBackground(String message, AVQuery extends AVObject> query,
SendCallback callback) {
if (!query.getClassName().equals(INSTALLATIONTAG)) {
if (callback != null) {
callback.done(new AVException(AVException.OTHER_CAUSE, "only installation query is valid"));
}
}
AVPush push = new AVPush();
push.setMessage(message);
push.setQuery(query);
push.sendInBackground(false, callback);
}
/**
* Sets the channel on which this push notification will be sent. The channel name must start with
* a letter and contain only letters, numbers, dashes, and underscores. A push can either have
* channels or a query. Setting this will unset the query.
*
* @param channel set push channel
*/
public void setChannel(String channel) {
channelSet.clear();
channelSet.add(channel);
}
/**
* Sets the collection of channels on which this push notification will be sent. Each channel name
* must start with a letter and contain only letters, numbers, dashes, and underscores. A push can
* either have channels or a query. Setting this will unset the query.
*
* @param channels set push channels
*/
public void setChannels(Collection channels) {
channelSet.clear();
channelSet.addAll(channels);
}
/**
* Sets the entire data of the push message. See the push guide for more details on the data
* format. This will overwrite any data specified in AVPush.setMessage(String).
*
* @param data push data
*/
public void setData(Map data) {
this.pushData.put("data", data);
}
/**
* Sets the entire data of the push message. See the push guide for more details on the data
* format. This will overwrite any data specified in AVPush.setMessage(String).
*
* @param data push data
*/
public void setData(JSONObject data) {
try {
Map map = new HashMap();
Iterator iter = data.keys();
while (iter.hasNext()) {
String key = (String) iter.next();
Object value = data.get(key);
map.put(key, value);
}
this.pushData.put("data", map);
} catch (Exception exception) {
throw new AVRuntimeException(exception);
}
}
private Date expirationDateTime() {
return new Date(expirationTime);
}
/**
* Set the push date at which the push will be sent.
*
* @param date The push date.
*/
public void setPushDate(Date date) {
this.pushDate = date;
}
/**
* Sets a UNIX epoch timestamp at which this notification should expire, in seconds (UTC). This
* notification will be sent to devices which are either online at the time the notification is
* sent, or which come online before the expiration time is reached. Because device clocks are not
* guaranteed to be accurate, most applications should instead use
* AVPush.setExpirationTimeInterval(long).
*
* @param time expire date
*/
public void setExpirationTime(long time) {
this.expirationTime = time;
}
/**
* Sets the time interval after which this notification should expire, in seconds. This
* notification will be sent to devices which are either online at the time the notification is
* sent, or which come online within the given number of seconds of the notification being
* received by AVOSCloud's server. An interval which is less than or equal to zero indicates that
* the message should only be sent to devices which are currently online.
*
* @param timeInterval expirationTimeInterval
*/
public void setExpirationTimeInterval(long timeInterval) {
this.expirationTimeInterval = timeInterval;
}
/**
* Sets the message that will be shown in the notification. This will overwrite any data specified
* in AVPush.setData(JSONObject).
*
* @param message set push message
*/
public void setMessage(String message) {
pushData.clear();
Map map = AVUtils.createStringObjectMap("alert", message);
pushData.put("data", map);
}
public void setPushToAndroid(boolean pushToAndroid) {
if (pushToAndroid) {
this.pushTarget.add("android");
} else {
this.pushTarget.remove("android");
}
}
public void setPushToIOS(boolean pushToIOS) {
if (pushToIOS) {
this.pushTarget.add("ios");
} else {
this.pushTarget.remove("ios");
}
}
public void setPushToWindowsPhone(boolean pushToWP) {
if (pushToWP) {
this.pushTarget.add("wp");
} else {
this.pushTarget.remove("wp");
}
}
/**
* Sets the query for this push for which this push notification will be sent. This query will be
* executed in the AVOSCloud cloud; this push notification will be sent to Installations which
* this query yields. A push can either have channels or a query. Setting this will unset the
* channels.
*
* @param query A query to which this push should target. This must be a AVInstallation query.
*/
public void setQuery(AVQuery extends AVObject> query) {
this.pushQuery = query;
}
/**
* 可以通过 cql来针对push进行筛选
*
* 请注意cql 的主体应该是_Installation表
*
* 请在设置cql的同时,不要设置pushTarget(ios,android,wp)
*
* @param cql cql for push
* @since 2.6.7
*/
public void setCloudQuery(String cql) {
this.cql = cql;
}
public boolean getProductionMode() {
return this.production;
}
/**
* 设定iOS推送是否是生产环境
*
*
* @since 2.6.9
* @param production,true为生产环境,默认是true
*/
public void setProductionMode(boolean production) {
this.production = production;
}
}