parent
c8fc70c908
commit
0b3835362f
@ -1,22 +0,0 @@ |
||||
*.iml |
||||
.gradle |
||||
/local.properties |
||||
/.idea |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
.externalNativeBuild |
||||
*.iml |
||||
.idea/ |
||||
.gradle |
||||
/local.properties |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
*.apk |
||||
*.ap_ |
||||
*.dex |
||||
*.class |
||||
bin/ |
||||
gen/ |
||||
local.properties |
@ -1,3 +0,0 @@ |
||||
# 推送库 |
||||
|
||||
目前集成的是极光推送,不允许暴露具体的推送 SDK 的 API 到其他模块中,必须采用统一的封装。 |
@ -1,26 +0,0 @@ |
||||
apply plugin: 'com.android.library' |
||||
|
||||
android { |
||||
compileSdkVersion rootProject.compileSdkVersion |
||||
buildToolsVersion rootProject.buildToolsVersion |
||||
|
||||
defaultConfig { |
||||
minSdkVersion rootProject.minSdkVersion |
||||
targetSdkVersion rootProject.targetSdkVersion |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
} |
||||
|
||||
compileOptions { |
||||
sourceCompatibility JavaVersion.VERSION_1_8 |
||||
targetCompatibility JavaVersion.VERSION_1_8 |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
||||
compileOnly androidLibraries.androidAnnotations |
||||
implementation 'cn.jiguang.sdk:jpush:3.1.6' |
||||
implementation 'cn.jiguang.sdk:jcore:1.2.5' |
||||
implementation thirdLibraries.timber |
||||
} |
@ -1,47 +0,0 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest |
||||
package="com.android.sdk.push" |
||||
xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
||||
<application> |
||||
|
||||
<!-- 用户自定义的广播接收器--> |
||||
<receiver |
||||
android:name=".jpush.JPushReceiver" |
||||
android:enabled="true" |
||||
android:exported="false"> |
||||
<intent-filter> |
||||
<!--Required 用户注册SDK的intent--> |
||||
<action android:name="cn.jpush.android.intent.REGISTRATION"/> |
||||
|
||||
<!--Required 用户接收SDK消息的intent--> |
||||
<action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED"/> |
||||
|
||||
<!--Required 用户接收SDK通知栏信息的intent--> |
||||
<action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED"/> |
||||
|
||||
<!--Required 用户打开自定义通知栏的intent,用户点击了通知。 一般情况下,用户不需要配置此 receiver action。 |
||||
如果开发者在 AndroidManifest.xml 里未配置此 receiver action,那么,SDK 会默认打开应用程序的主 Activity,相当于用户点击桌面图标的效果。--> |
||||
<action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED"/> |
||||
|
||||
<!-- 接收网络变化 连接/断开 since 1.6.3 --> |
||||
<action android:name="cn.jpush.android.intent.CONNECTION"/> |
||||
<category android:name="${JPUSH_PKGNAME}"/> |
||||
|
||||
</intent-filter> |
||||
</receiver> |
||||
|
||||
<!-- 用户自定义接收消息器,3.0.7 开始支持,目前新 tag/alias 接口设置结果会在该广播接收器对应的方法中回调--> |
||||
<receiver |
||||
android:name=".jpush.TagAliasJPushMessageReceiver" |
||||
android:enabled="true" |
||||
android:exported="false"> |
||||
<intent-filter> |
||||
<action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE"/> |
||||
<category android:name="${JPUSH_PKGNAME}"/> |
||||
</intent-filter> |
||||
</receiver> |
||||
|
||||
</application> |
||||
|
||||
</manifest> |
@ -1,27 +0,0 @@ |
||||
package com.android.sdk.push; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: 1169654504@qq.com |
||||
* Date : 2017-03-09 11:31 |
||||
*/ |
||||
public interface MessageHandler { |
||||
|
||||
/** |
||||
* 处理透传消息 |
||||
* |
||||
* @param pushMessage 消息 |
||||
*/ |
||||
void onDirectMessageArrived(PushMessage pushMessage); |
||||
|
||||
/** |
||||
* 通知栏消息被点击 |
||||
*/ |
||||
void handleOnNotificationMessageClicked(PushMessage pushMessage); |
||||
|
||||
/** |
||||
* 通知栏消息到达 |
||||
*/ |
||||
void onNotificationMessageArrived(PushMessage pushMessage); |
||||
|
||||
} |
@ -1,39 +0,0 @@ |
||||
package com.android.sdk.push; |
||||
|
||||
import android.app.Activity; |
||||
import android.support.annotation.NonNull; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: 1169654504@qq.com |
||||
* Date : 2017-03-09 11:31 |
||||
*/ |
||||
public interface Push { |
||||
|
||||
void registerPush(@NonNull final PushCallBack pushCallBack); |
||||
|
||||
void setAlias(String alias); |
||||
|
||||
void clearAlias(); |
||||
|
||||
void setTag(String tag); |
||||
|
||||
void addTag(String tag); |
||||
|
||||
void deleteTag(String tag); |
||||
|
||||
void clearTag(); |
||||
|
||||
void enablePush(); |
||||
|
||||
void disablePush(); |
||||
|
||||
void setMessageHandler(MessageHandler messageHandler); |
||||
|
||||
MessageHandler getMessageHandler(); |
||||
|
||||
void onActivityCreate(Activity activity); |
||||
|
||||
void setChannel(String channel); |
||||
|
||||
} |
@ -1,7 +0,0 @@ |
||||
package com.android.sdk.push; |
||||
|
||||
|
||||
public interface PushCallBack { |
||||
void onRegisterPushSuccess(String registrationID); |
||||
void onRegisterPushFail(); |
||||
} |
@ -1,53 +0,0 @@ |
||||
package com.android.sdk.push; |
||||
|
||||
import android.app.Application; |
||||
import android.text.TextUtils; |
||||
|
||||
import com.android.sdk.push.jpush.JPush; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: 1169654504@qq.com |
||||
* Date : 2017-03-03 16:22 |
||||
*/ |
||||
public class PushContext { |
||||
|
||||
private static Application mApplication; |
||||
private static boolean isDebug; |
||||
private static Push sPush; |
||||
|
||||
private static String APP_ID; |
||||
private static String APP_KEY; |
||||
|
||||
public static void configPush(String appKey, String appId) { |
||||
APP_KEY = appKey; |
||||
APP_ID = appId; |
||||
} |
||||
|
||||
public static boolean isPushConfigured() { |
||||
return !TextUtils.isEmpty(APP_ID) && !TextUtils.isEmpty(APP_KEY); |
||||
} |
||||
|
||||
public static void init(Application application, boolean debug) { |
||||
isDebug = debug; |
||||
mApplication = application; |
||||
initPush(); |
||||
} |
||||
|
||||
private static void initPush() { |
||||
sPush = new JPush(mApplication); |
||||
} |
||||
|
||||
public static Push getPush() { |
||||
return sPush; |
||||
} |
||||
|
||||
public static boolean isDebug() { |
||||
return isDebug; |
||||
} |
||||
|
||||
public static Application getApplication() { |
||||
return mApplication; |
||||
} |
||||
|
||||
} |
@ -1,76 +0,0 @@ |
||||
package com.android.sdk.push; |
||||
|
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
public class PushMessage { |
||||
|
||||
private int messageId; |
||||
private int notificationId; |
||||
private String alertType; |
||||
private String content; |
||||
private String extra; |
||||
private String title; |
||||
|
||||
public int getNotificationId() { |
||||
return notificationId; |
||||
} |
||||
|
||||
public void setNotificationId(int notificationId) { |
||||
this.notificationId = notificationId; |
||||
} |
||||
|
||||
public String getAlertType() { |
||||
return alertType; |
||||
} |
||||
|
||||
public void setAlertType(String alertType) { |
||||
this.alertType = alertType; |
||||
} |
||||
|
||||
public String getTitle() { |
||||
return title; |
||||
} |
||||
|
||||
public void setTitle(String title) { |
||||
this.title = title; |
||||
} |
||||
|
||||
public String getContent() { |
||||
return content; |
||||
} |
||||
|
||||
public void setContent(String content) { |
||||
this.content = content; |
||||
} |
||||
|
||||
public String getExtra() { |
||||
return extra; |
||||
} |
||||
|
||||
public void setExtra(String extra) { |
||||
this.extra = extra; |
||||
} |
||||
|
||||
public int getMessageId() { |
||||
return messageId; |
||||
} |
||||
|
||||
public void setMessageId(int messageId) { |
||||
this.messageId = messageId; |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "PushMessage{" + |
||||
"messageiId=" + messageId + |
||||
", notificationId=" + notificationId + |
||||
", alertType=" + alertType + |
||||
", content='" + content + '\'' + |
||||
", extra='" + extra + '\'' + |
||||
", title='" + title + '\'' + |
||||
'}'; |
||||
} |
||||
|
||||
} |
@ -1,25 +0,0 @@ |
||||
package com.android.sdk.push; |
||||
|
||||
import android.content.Context; |
||||
import android.content.SharedPreferences; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2019-02-26 11:36 |
||||
*/ |
||||
public class Utils { |
||||
|
||||
private static final String PUSH_SP_NAME = "push_sp_name"; |
||||
|
||||
public static void savePushId(String key, String id) { |
||||
SharedPreferences sharedPreferences = PushContext.getApplication().getSharedPreferences(PUSH_SP_NAME, Context.MODE_PRIVATE); |
||||
sharedPreferences.edit().putString(key, id).apply(); |
||||
} |
||||
|
||||
public static String getPushId(String key) { |
||||
SharedPreferences sharedPreferences = PushContext.getApplication().getSharedPreferences(PUSH_SP_NAME, Context.MODE_PRIVATE); |
||||
return sharedPreferences.getString(key, ""); |
||||
} |
||||
|
||||
} |
@ -1,16 +0,0 @@ |
||||
package com.android.sdk.push.exception; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: 1169654504@qq.com |
||||
* Date : 2017-05-18 12:00 |
||||
*/ |
||||
public class PushUnConfigException extends RuntimeException { |
||||
|
||||
private static final String MESSAGE = "you have not deployed the %s id"; |
||||
|
||||
public PushUnConfigException(String message) { |
||||
super(String.format(MESSAGE, message)); |
||||
} |
||||
|
||||
} |
@ -1,124 +0,0 @@ |
||||
package com.android.sdk.push.jpush; |
||||
|
||||
import android.app.Activity; |
||||
import android.app.Application; |
||||
import android.content.Context; |
||||
import android.support.annotation.NonNull; |
||||
import android.text.TextUtils; |
||||
|
||||
import com.android.sdk.push.MessageHandler; |
||||
import com.android.sdk.push.Push; |
||||
import com.android.sdk.push.PushCallBack; |
||||
import com.android.sdk.push.PushContext; |
||||
import com.android.sdk.push.Utils; |
||||
|
||||
import cn.jpush.android.api.JPushInterface; |
||||
import timber.log.Timber; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2019-01-26 17:44 |
||||
*/ |
||||
public class JPush implements Push { |
||||
|
||||
private Context mContext; |
||||
private MessageHandler mMessageHandler; |
||||
private PushCallBack mPushCallBack; |
||||
|
||||
static final String JPUSH_ID_KET = "jpush_id_key"; |
||||
|
||||
public JPush(Application mApplication) { |
||||
mContext = mApplication.getApplicationContext(); |
||||
} |
||||
|
||||
@Override |
||||
public void registerPush(@NonNull PushCallBack pushCallBack) { |
||||
this.mPushCallBack = pushCallBack; |
||||
//给 JPushReceiver 设置 JPush
|
||||
JPushReceiver.sJPush = this; |
||||
// 设置开启日志,发布时请关闭日志
|
||||
JPushInterface.setDebugMode(PushContext.isDebug()); |
||||
// 初始化极光推送服务
|
||||
JPushInterface.init(mContext); |
||||
String registrationID = getRegistrationID(); |
||||
Timber.d("jpush registrationID = " + registrationID); |
||||
boolean isRegistrationSuccess = !TextUtils.isEmpty(registrationID); |
||||
if (isRegistrationSuccess) { |
||||
this.mPushCallBack.onRegisterPushSuccess(registrationID); |
||||
} |
||||
} |
||||
|
||||
private String getRegistrationID() { |
||||
String registrationID = JPushInterface.getRegistrationID(mContext); |
||||
if (TextUtils.isEmpty(registrationID)) { |
||||
registrationID = Utils.getPushId(JPUSH_ID_KET); |
||||
} |
||||
return registrationID; |
||||
} |
||||
|
||||
@Override |
||||
public void setAlias(String alias) { |
||||
JPushUtils.setAlias(mContext, alias); |
||||
} |
||||
|
||||
@Override |
||||
public void clearAlias() { |
||||
JPushUtils.clearAlias(mContext); |
||||
} |
||||
|
||||
@Override |
||||
public void setTag(String tag) { |
||||
JPushUtils.setTag(mContext, tag); |
||||
} |
||||
|
||||
@Override |
||||
public void addTag(String tag) { |
||||
JPushUtils.deleteTag(mContext, tag); |
||||
} |
||||
|
||||
@Override |
||||
public void deleteTag(String tag) { |
||||
JPushUtils.setTag(mContext, tag); |
||||
} |
||||
|
||||
@Override |
||||
public void clearTag() { |
||||
JPushUtils.clearTags(mContext); |
||||
} |
||||
|
||||
@Override |
||||
public void enablePush() { |
||||
JPushInterface.resumePush(mContext); |
||||
} |
||||
|
||||
@Override |
||||
public void disablePush() { |
||||
JPushInterface.stopPush(mContext); |
||||
} |
||||
|
||||
@Override |
||||
public void setMessageHandler(MessageHandler messageHandler) { |
||||
this.mMessageHandler = messageHandler; |
||||
} |
||||
|
||||
@Override |
||||
public MessageHandler getMessageHandler() { |
||||
return mMessageHandler; |
||||
} |
||||
|
||||
PushCallBack getPushCallBack() { |
||||
return mPushCallBack; |
||||
} |
||||
|
||||
@Override |
||||
public void setChannel(String channel) { |
||||
JPushInterface.setChannel(mContext, channel); |
||||
} |
||||
|
||||
@Override |
||||
public void onActivityCreate(Activity activity) { |
||||
// no op
|
||||
} |
||||
|
||||
} |
@ -1,128 +0,0 @@ |
||||
package com.android.sdk.push.jpush; |
||||
|
||||
import android.content.BroadcastReceiver; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
import android.support.annotation.NonNull; |
||||
|
||||
import com.android.sdk.push.PushContext; |
||||
import com.android.sdk.push.PushMessage; |
||||
import com.android.sdk.push.Utils; |
||||
|
||||
import cn.jpush.android.api.JPushInterface; |
||||
import timber.log.Timber; |
||||
|
||||
import static com.android.sdk.push.jpush.JPush.JPUSH_ID_KET; |
||||
|
||||
/** |
||||
* 极光推送-消息接收广播 |
||||
* |
||||
* @author Wangwb |
||||
* Email: 253123123@qq.com |
||||
* Date : 2019-01-28 11:21 |
||||
*/ |
||||
public class JPushReceiver extends BroadcastReceiver { |
||||
|
||||
static JPush sJPush; |
||||
|
||||
@Override |
||||
public void onReceive(Context context, Intent intent) { |
||||
try { |
||||
processMessage(intent); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
private void processMessage(Intent intent) { |
||||
Bundle bundle = intent.getExtras(); |
||||
|
||||
if (PushContext.isDebug()) { |
||||
Timber.d("[JPushReceiver] onReceive - " + intent.getAction() + ", extras: " + JPushUtils.printBundle(bundle)); |
||||
} |
||||
|
||||
if (bundle == null) { |
||||
return; |
||||
} |
||||
|
||||
if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) { |
||||
|
||||
processRegisterSuccess(bundle); |
||||
|
||||
} else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) { |
||||
|
||||
processMessageReceived(bundle); |
||||
|
||||
} else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) { |
||||
|
||||
processNotificationMessageReceived(bundle); |
||||
|
||||
} else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) { |
||||
|
||||
//目前没有配置这个 action,不会接收此类消息
|
||||
processNotificationMessageClicked(bundle); |
||||
|
||||
} else if (JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) { |
||||
|
||||
Timber.w("[JPushReceiver]" + intent.getAction() + " connected state change to " + intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false)); |
||||
|
||||
} else { |
||||
Timber.d("[JPushReceiver] Unhandled intent - " + intent.getAction()); |
||||
} |
||||
|
||||
} |
||||
|
||||
private void processNotificationMessageClicked(Bundle bundle) { |
||||
Timber.d("[JPushReceiver] 接收到推送下来的通知被点击了"); |
||||
PushMessage pushMessage = extractMessage(bundle); |
||||
sJPush.getMessageHandler().handleOnNotificationMessageClicked(pushMessage); |
||||
} |
||||
|
||||
// 在这里可以做些统计,或者做些其他工作
|
||||
private void processNotificationMessageReceived(Bundle bundle) { |
||||
Timber.d("[JPushReceiver] 接收到推送下来的通知"); |
||||
PushMessage pushMessage = extractMessage(bundle); |
||||
sJPush.getMessageHandler().onNotificationMessageArrived(pushMessage); |
||||
} |
||||
|
||||
@NonNull |
||||
private PushMessage extractMessage(Bundle bundle) { |
||||
int notificationId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID); |
||||
String alertType = bundle.getString(JPushInterface.EXTRA_ALERT_TYPE); |
||||
String alert = bundle.getString(JPushInterface.EXTRA_ALERT); |
||||
String title = bundle.getString(JPushInterface.EXTRA_NOTIFICATION_TITLE); |
||||
String extras = bundle.getString(JPushInterface.EXTRA_EXTRA); |
||||
|
||||
PushMessage pushMessage = new PushMessage(); |
||||
pushMessage.setTitle(title); |
||||
pushMessage.setContent(alert); |
||||
pushMessage.setExtra(extras); |
||||
pushMessage.setNotificationId(notificationId); |
||||
pushMessage.setAlertType(alertType); |
||||
return pushMessage; |
||||
} |
||||
|
||||
private void processRegisterSuccess(Bundle bundle) { |
||||
String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID); |
||||
Timber.d("[JPushReceiver] JPush 用户注册成功,接收Registration Id : " + regId); |
||||
//you can send the Registration Id to your server...
|
||||
Utils.savePushId(JPUSH_ID_KET, regId); |
||||
sJPush.getPushCallBack().onRegisterPushSuccess(regId); |
||||
} |
||||
|
||||
// 自定义消息不会展示在通知栏,完全要开发者写代码去处理
|
||||
private void processMessageReceived(Bundle bundle) { |
||||
Timber.d("[JPushReceiver] 接收到推送下来的透传消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE)); |
||||
|
||||
String message = bundle.getString(JPushInterface.EXTRA_MESSAGE); |
||||
String extras = bundle.getString(JPushInterface.EXTRA_EXTRA); |
||||
|
||||
PushMessage pushMessage = new PushMessage(); |
||||
pushMessage.setContent(message); |
||||
pushMessage.setExtra(extras); |
||||
|
||||
sJPush.getMessageHandler().onDirectMessageArrived(pushMessage); |
||||
} |
||||
|
||||
} |
@ -1,195 +0,0 @@ |
||||
package com.android.sdk.push.jpush; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.content.Context; |
||||
import android.content.pm.ApplicationInfo; |
||||
import android.content.pm.PackageManager; |
||||
import android.net.ConnectivityManager; |
||||
import android.net.NetworkInfo; |
||||
import android.os.Bundle; |
||||
import android.support.annotation.NonNull; |
||||
import android.text.TextUtils; |
||||
|
||||
import org.json.JSONException; |
||||
import org.json.JSONObject; |
||||
|
||||
import java.util.Iterator; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import cn.jpush.android.api.JPushInterface; |
||||
import timber.log.Timber; |
||||
|
||||
import static com.android.sdk.push.jpush.TagAliasOperatorHelper.ACTION_ADD; |
||||
import static com.android.sdk.push.jpush.TagAliasOperatorHelper.ACTION_CLEAN; |
||||
import static com.android.sdk.push.jpush.TagAliasOperatorHelper.ACTION_DELETE; |
||||
import static com.android.sdk.push.jpush.TagAliasOperatorHelper.ACTION_SET; |
||||
|
||||
/** |
||||
* @author Wangwb |
||||
* Email: 253123123@qq.com |
||||
* Date : 2019-01-28 11:29 |
||||
*/ |
||||
class JPushUtils { |
||||
|
||||
private static final String TAG = "JPushReceiver"; |
||||
|
||||
/** |
||||
* 打印 Bundle Extras |
||||
*/ |
||||
static String printBundle(Bundle bundle) { |
||||
if (bundle == null) { |
||||
return "null"; |
||||
} |
||||
|
||||
StringBuilder sb = new StringBuilder(); |
||||
|
||||
for (String key : bundle.keySet()) { |
||||
switch (key) { |
||||
case JPushInterface.EXTRA_NOTIFICATION_ID: |
||||
sb.append("\nkey:").append(key).append(", value:").append(bundle.getInt(key)); |
||||
break; |
||||
case JPushInterface.EXTRA_CONNECTION_CHANGE: |
||||
sb.append("\nkey:").append(key).append(", value:").append(bundle.getBoolean(key)); |
||||
break; |
||||
case JPushInterface.EXTRA_EXTRA: |
||||
if (TextUtils.isEmpty(bundle.getString(JPushInterface.EXTRA_EXTRA))) { |
||||
Timber.i(TAG, "This message has no Extra data"); |
||||
continue; |
||||
} |
||||
|
||||
try { |
||||
JSONObject json = new JSONObject(bundle.getString(JPushInterface.EXTRA_EXTRA)); |
||||
Iterator<String> it = json.keys(); |
||||
|
||||
while (it.hasNext()) { |
||||
String myKey = it.next(); |
||||
sb.append("\nkey:").append(key).append(", value: [").append(myKey).append(" - ").append(json.optString(myKey)).append("]"); |
||||
} |
||||
} catch (JSONException e) { |
||||
Timber.e(TAG, "Get message extra JSON error!"); |
||||
} |
||||
break; |
||||
default: |
||||
sb.append("\nkey:").append(key).append(", value:").append(bundle.get(key)); |
||||
break; |
||||
} |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* 获取极光推送AppKey |
||||
*/ |
||||
@SuppressWarnings("unused") |
||||
static String appKey(Context context) { |
||||
Bundle metaData = null; |
||||
String appKey = null; |
||||
try { |
||||
ApplicationInfo ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); |
||||
if (null != ai) |
||||
metaData = ai.metaData; |
||||
if (null != metaData) { |
||||
appKey = metaData.getString("JPUSH_APPKEY"); |
||||
Timber.d("JPush AppKey: " + appKey + ", pkg: " + context.getPackageName()); |
||||
if ((null == appKey) || appKey.length() != 24) { |
||||
appKey = null; |
||||
} |
||||
} |
||||
} catch (PackageManager.NameNotFoundException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return appKey; |
||||
} |
||||
|
||||
/** |
||||
* 校验Tag Alias 只能是数字,英文字母和中文 |
||||
*/ |
||||
@SuppressWarnings("all") |
||||
private static boolean isValidTagAndAlias(String s) { |
||||
Pattern p = Pattern.compile("^[\u4E00-\u9FA50-9a-zA-Z_!@#$&*+=.|]+$"); |
||||
Matcher m = p.matcher(s); |
||||
return m.matches(); |
||||
} |
||||
|
||||
static boolean isConnected(Context context) { |
||||
ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
||||
@SuppressLint("MissingPermission") |
||||
NetworkInfo info = conn.getActiveNetworkInfo(); |
||||
return (info == null || !info.isConnected()); |
||||
} |
||||
|
||||
/** |
||||
* 获取设备ID |
||||
*/ |
||||
@SuppressWarnings("unused") |
||||
static String getDeviceId(Context context) { |
||||
return JPushInterface.getUdid(context); |
||||
} |
||||
|
||||
static void setTag(Context context, String tag) { |
||||
if (!JPushUtils.isValidTagAndAlias(tag)) { |
||||
Timber.e("Tag Alias 命名不符合规范"); |
||||
return; |
||||
} |
||||
|
||||
TagAliasOperatorHelper.TagAliasBean tagAliasBean = createTagAliasBean(tag); |
||||
tagAliasBean.action = ACTION_SET; |
||||
|
||||
TagAliasOperatorHelper.getInstance().handleAction(context, ++TagAliasOperatorHelper.sequence, tagAliasBean); |
||||
} |
||||
|
||||
static void deleteTag(Context context, String tag) { |
||||
if (!JPushUtils.isValidTagAndAlias(tag)) { |
||||
Timber.e("Tag Alias 命名不符合规范"); |
||||
return; |
||||
} |
||||
|
||||
TagAliasOperatorHelper.TagAliasBean tagAliasBean = createTagAliasBean(tag); |
||||
tagAliasBean.action = ACTION_DELETE; |
||||
|
||||
TagAliasOperatorHelper.getInstance().handleAction(context, ++TagAliasOperatorHelper.sequence, tagAliasBean); |
||||
} |
||||
|
||||
static void clearTags(Context context) { |
||||
TagAliasOperatorHelper.TagAliasBean tagAliasBean = createTagAliasBean(null); |
||||
tagAliasBean.action = ACTION_CLEAN; |
||||
|
||||
TagAliasOperatorHelper.getInstance().handleAction(context, ++TagAliasOperatorHelper.sequence, tagAliasBean); |
||||
} |
||||
|
||||
@NonNull |
||||
private static TagAliasOperatorHelper.TagAliasBean createTagAliasBean(String tag) { |
||||
TagAliasOperatorHelper.TagAliasBean tagAliasBean = new TagAliasOperatorHelper.TagAliasBean(); |
||||
tagAliasBean.isAliasAction = false; |
||||
|
||||
if (!TextUtils.isEmpty(tag)) { |
||||
LinkedHashSet<String> tags = new LinkedHashSet<>(); |
||||
tags.add(tag); |
||||
tagAliasBean.tags = tags; |
||||
} |
||||
|
||||
return tagAliasBean; |
||||
} |
||||
|
||||
static void setAlias(Context context, String alias) { |
||||
TagAliasOperatorHelper.TagAliasBean tagAliasBean = new TagAliasOperatorHelper.TagAliasBean(); |
||||
|
||||
tagAliasBean.action = ACTION_ADD; |
||||
tagAliasBean.isAliasAction = true; |
||||
tagAliasBean.alias = alias; |
||||
|
||||
TagAliasOperatorHelper.getInstance().handleAction(context, ++TagAliasOperatorHelper.sequence, tagAliasBean); |
||||
} |
||||
|
||||
static void clearAlias(Context context) { |
||||
TagAliasOperatorHelper.TagAliasBean tagAliasBean = new TagAliasOperatorHelper.TagAliasBean(); |
||||
|
||||
tagAliasBean.action = ACTION_DELETE; |
||||
tagAliasBean.isAliasAction = true; |
||||
|
||||
TagAliasOperatorHelper.getInstance().handleAction(context, ++TagAliasOperatorHelper.sequence, tagAliasBean); |
||||
} |
||||
|
||||
} |
@ -1,37 +0,0 @@ |
||||
package com.android.sdk.push.jpush; |
||||
|
||||
import android.content.Context; |
||||
|
||||
import cn.jpush.android.api.JPushMessage; |
||||
import cn.jpush.android.service.JPushMessageReceiver; |
||||
|
||||
/** |
||||
* 自定义 JPush message 接收器,包括操作 tag/alias 的结果返回(仅仅包含 tag/alias 新接口部分) |
||||
*/ |
||||
public class TagAliasJPushMessageReceiver extends JPushMessageReceiver { |
||||
|
||||
@Override |
||||
public void onTagOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
TagAliasOperatorHelper.getInstance().onTagOperatorResult(context, jPushMessage); |
||||
super.onTagOperatorResult(context, jPushMessage); |
||||
} |
||||
|
||||
@Override |
||||
public void onCheckTagOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
TagAliasOperatorHelper.getInstance().onCheckTagOperatorResult(context, jPushMessage); |
||||
super.onCheckTagOperatorResult(context, jPushMessage); |
||||
} |
||||
|
||||
@Override |
||||
public void onAliasOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
TagAliasOperatorHelper.getInstance().onAliasOperatorResult(context, jPushMessage); |
||||
super.onAliasOperatorResult(context, jPushMessage); |
||||
} |
||||
|
||||
@Override |
||||
public void onMobileNumberOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
TagAliasOperatorHelper.getInstance().onMobileNumberOperatorResult(context, jPushMessage); |
||||
super.onMobileNumberOperatorResult(context, jPushMessage); |
||||
} |
||||
|
||||
} |
@ -1,412 +0,0 @@ |
||||
package com.android.sdk.push.jpush; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.content.Context; |
||||
import android.os.Handler; |
||||
import android.os.Message; |
||||
import android.support.annotation.NonNull; |
||||
import android.util.SparseArray; |
||||
|
||||
import java.util.Locale; |
||||
import java.util.Objects; |
||||
import java.util.Set; |
||||
|
||||
import cn.jpush.android.api.JPushInterface; |
||||
import cn.jpush.android.api.JPushMessage; |
||||
import timber.log.Timber; |
||||
|
||||
/** |
||||
* 处理 tag alias 相关的逻辑 |
||||
*/ |
||||
class TagAliasOperatorHelper { |
||||
|
||||
private static final String TAG = "JIGUANG-TagAliasHelper"; |
||||
|
||||
static int sequence = 1; |
||||
|
||||
/** |
||||
* 增加 |
||||
*/ |
||||
static final int ACTION_ADD = 1; |
||||
/** |
||||
* 覆盖 |
||||
*/ |
||||
static final int ACTION_SET = 2; |
||||
/** |
||||
* 删除部分 |
||||
*/ |
||||
static final int ACTION_DELETE = 3; |
||||
/** |
||||
* 删除所有 |
||||
*/ |
||||
static final int ACTION_CLEAN = 4; |
||||
/** |
||||
* 查询 |
||||
*/ |
||||
static final int ACTION_GET = 5; |
||||
/** |
||||
* 检查 |
||||
*/ |
||||
static final int ACTION_CHECK = 6; |
||||
|
||||
private static final int DELAY_SEND_ACTION = 1; |
||||
|
||||
private static final int DELAY_SET_MOBILE_NUMBER_ACTION = 2; |
||||
|
||||
private Context context; |
||||
|
||||
@SuppressLint("StaticFieldLeak") |
||||
private static TagAliasOperatorHelper mInstance; |
||||
|
||||
private TagAliasOperatorHelper() { |
||||
} |
||||
|
||||
public static TagAliasOperatorHelper getInstance() { |
||||
if (mInstance == null) { |
||||
synchronized (TagAliasOperatorHelper.class) { |
||||
if (mInstance == null) { |
||||
mInstance = new TagAliasOperatorHelper(); |
||||
} |
||||
} |
||||
} |
||||
return mInstance; |
||||
} |
||||
|
||||
public void init(Context context) { |
||||
if (context != null) { |
||||
this.context = context.getApplicationContext(); |
||||
} |
||||
} |
||||
|
||||
private SparseArray<Object> setActionCache = new SparseArray<>(); |
||||
|
||||
public Object get(int sequence) { |
||||
return setActionCache.get(sequence); |
||||
} |
||||
|
||||
public Object remove(int sequence) { |
||||
return setActionCache.get(sequence); |
||||
} |
||||
|
||||
private void put(int sequence, Object tagAliasBean) { |
||||
setActionCache.put(sequence, tagAliasBean); |
||||
} |
||||
|
||||
@SuppressLint("HandlerLeak") |
||||
private Handler delaySendHandler = new Handler() { |
||||
@Override |
||||
public void handleMessage(Message msg) { |
||||
switch (msg.what) { |
||||
case DELAY_SEND_ACTION: |
||||
if (msg.obj instanceof TagAliasBean) { |
||||
Timber.w(TAG, "on delay time"); |
||||
sequence++; |
||||
TagAliasBean tagAliasBean = (TagAliasBean) msg.obj; |
||||
setActionCache.put(sequence, tagAliasBean); |
||||
if (context != null) { |
||||
handleAction(context, sequence, tagAliasBean); |
||||
} else { |
||||
Timber.w(TAG, "#unexcepted - context was null"); |
||||
} |
||||
} else { |
||||
Timber.w(TAG, "#unexcepted - msg obj was incorrect"); |
||||
} |
||||
break; |
||||
case DELAY_SET_MOBILE_NUMBER_ACTION: |
||||
if (msg.obj instanceof String) { |
||||
Timber.w(TAG, "retry set mobile number"); |
||||
sequence++; |
||||
String mobileNumber = (String) msg.obj; |
||||
setActionCache.put(sequence, mobileNumber); |
||||
if (context != null) { |
||||
handleAction(context, sequence, mobileNumber); |
||||
} else { |
||||
Timber.w(TAG, "#unexcepted - context was null"); |
||||
} |
||||
} else { |
||||
Timber.w(TAG, "#unexcepted - msg obj was incorrect"); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
private void handleAction(Context context, int sequence, String mobileNumber) { |
||||
put(sequence, mobileNumber); |
||||
Timber.d(TAG, "sequence:" + sequence + ",mobileNumber:" + mobileNumber); |
||||
JPushInterface.setMobileNumber(context, sequence, mobileNumber); |
||||
} |
||||
|
||||
/** |
||||
* 处理设置tag |
||||
*/ |
||||
void handleAction(Context context, int sequence, TagAliasBean tagAliasBean) { |
||||
init(context); |
||||
if (tagAliasBean == null) { |
||||
Timber.w(TAG, "tagAliasBean was null"); |
||||
return; |
||||
} |
||||
put(sequence, tagAliasBean); |
||||
if (tagAliasBean.isAliasAction) { |
||||
switch (tagAliasBean.action) { |
||||
case ACTION_GET: |
||||
JPushInterface.getAlias(context, sequence); |
||||
break; |
||||
case ACTION_DELETE: |
||||
JPushInterface.deleteAlias(context, sequence); |
||||
break; |
||||
case ACTION_SET: |
||||
JPushInterface.setAlias(context, sequence, tagAliasBean.alias); |
||||
break; |
||||
default: |
||||
Timber.w(TAG, "unsupport alias action type"); |
||||
} |
||||
} else { |
||||
switch (tagAliasBean.action) { |
||||
case ACTION_ADD: |
||||
JPushInterface.addTags(context, sequence, tagAliasBean.tags); |
||||
break; |
||||
case ACTION_SET: |
||||
JPushInterface.setTags(context, sequence, tagAliasBean.tags); |
||||
break; |
||||
case ACTION_DELETE: |
||||
JPushInterface.deleteTags(context, sequence, tagAliasBean.tags); |
||||
break; |
||||
case ACTION_CHECK: |
||||
//一次只能check一个tag
|
||||
String tag = (String) Objects.requireNonNull(tagAliasBean.tags.toArray())[0]; |
||||
JPushInterface.checkTagBindState(context, sequence, tag); |
||||
break; |
||||
case ACTION_GET: |
||||
JPushInterface.getAllTags(context, sequence); |
||||
break; |
||||
case ACTION_CLEAN: |
||||
JPushInterface.cleanTags(context, sequence); |
||||
break; |
||||
default: |
||||
Timber.w(TAG, "unsupport tag action type"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private boolean RetryActionIfNeeded(int errorCode, TagAliasBean tagAliasBean) { |
||||
if (JPushUtils.isConnected(context)) { |
||||
Timber.w(TAG, "no network"); |
||||
return true; |
||||
} |
||||
//返回的错误码为6002 超时,6014 服务器繁忙,都建议延迟重试
|
||||
if (errorCode == 6002 || errorCode == 6014) { |
||||
Timber.d(TAG, "need retry"); |
||||
if (tagAliasBean != null) { |
||||
Message message = new Message(); |
||||
message.what = DELAY_SEND_ACTION; |
||||
message.obj = tagAliasBean; |
||||
delaySendHandler.sendMessageDelayed(message, 1000 * 60); |
||||
String logs = getRetryStr(tagAliasBean.isAliasAction, tagAliasBean.action, errorCode); |
||||
Timber.w(TAG, logs); |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
private boolean RetrySetMObileNumberActionIfNeeded(int errorCode, String mobileNumber) { |
||||
if (JPushUtils.isConnected(context)) { |
||||
Timber.w(TAG, "no network"); |
||||
return false; |
||||
} |
||||
//返回的错误码为6002 超时,6024 服务器内部错误,建议稍后重试
|
||||
if (errorCode == 6002 || errorCode == 6024) { |
||||
Timber.d(TAG, "need retry"); |
||||
Message message = new Message(); |
||||
message.what = DELAY_SET_MOBILE_NUMBER_ACTION; |
||||
message.obj = mobileNumber; |
||||
delaySendHandler.sendMessageDelayed(message, 1000 * 60); |
||||
String str = "Failed to set mobile number due to %s. Try again after 60s."; |
||||
str = String.format(Locale.ENGLISH, str, |
||||
(errorCode == 6002 ? "timeout" : "server internal error”")); |
||||
Timber.w(TAG, str); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private String getRetryStr(boolean isAliasAction, int actionType, int errorCode) { |
||||
String str = "Failed to %s %s due to %s. Try again after 60s."; |
||||
str = String.format(Locale.ENGLISH, str, getActionStr(actionType), |
||||
(isAliasAction ? "alias" : " tags"), (errorCode == 6002 ? "timeout" : "server too busy")); |
||||
return str; |
||||
} |
||||
|
||||
private String getActionStr(int actionType) { |
||||
switch (actionType) { |
||||
case ACTION_ADD: |
||||
return "add"; |
||||
case ACTION_SET: |
||||
return "set"; |
||||
case ACTION_DELETE: |
||||
return "delete"; |
||||
case ACTION_GET: |
||||
return "get"; |
||||
case ACTION_CLEAN: |
||||
return "clean"; |
||||
case ACTION_CHECK: |
||||
return "check"; |
||||
} |
||||
return "unkonw operation"; |
||||
} |
||||
|
||||
void onTagOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
int sequence = jPushMessage.getSequence(); |
||||
Timber.i(TAG, "action - onTagOperatorResult, sequence:" + sequence + ",tags:" + jPushMessage.getTags()); |
||||
if (jPushMessage.getTags() != null) { |
||||
Timber.i(TAG, "tags size:" + jPushMessage.getTags().size()); |
||||
} |
||||
|
||||
init(context); |
||||
|
||||
// 根据sequence从之前操作缓存中获取缓存记录
|
||||
TagAliasBean tagAliasBean = (TagAliasBean) setActionCache.get(sequence); |
||||
if (tagAliasBean == null) { |
||||
Timber.w(TAG, "获取缓存记录失败"); |
||||
return; |
||||
} |
||||
if (jPushMessage.getErrorCode() == 0) { |
||||
Timber.i(TAG, "action - modify tag Success,sequence:" + sequence); |
||||
setActionCache.remove(sequence); |
||||
String logs = getActionStr(tagAliasBean.action) + " tags success"; |
||||
Timber.w(TAG, logs); |
||||
// 极光推送已经初始化失败
|
||||
} else { |
||||
String logs = "Failed to " + getActionStr(tagAliasBean.action) + " tags"; |
||||
if (jPushMessage.getErrorCode() == 6018) { |
||||
//tag数量超过限制,需要先清除一部分再 add
|
||||
logs += ", tags is exceed limit need to clean"; |
||||
} |
||||
logs += ", errorCode:" + jPushMessage.getErrorCode(); |
||||
Timber.w(TAG, logs); |
||||
if (RetryActionIfNeeded(jPushMessage.getErrorCode(), tagAliasBean)) { |
||||
Timber.w(TAG, logs); |
||||
} |
||||
// 极光推送已经初始化成功
|
||||
} |
||||
} |
||||
|
||||
void onCheckTagOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
int sequence = jPushMessage.getSequence(); |
||||
Timber.i(TAG, "action - onCheckTagOperatorResult, sequence:" |
||||
+ sequence |
||||
+ ",checktag:" |
||||
+ jPushMessage.getCheckTag()); |
||||
|
||||
init(context); |
||||
|
||||
// 根据sequence从之前操作缓存中获取缓存记录
|
||||
TagAliasBean tagAliasBean = (TagAliasBean) setActionCache.get(sequence); |
||||
if (tagAliasBean == null) { |
||||
Timber.w(TAG, "获取缓存记录失败"); |
||||
return; |
||||
} |
||||
if (jPushMessage.getErrorCode() == 0) { |
||||
Timber.i(TAG, "tagBean:" + tagAliasBean); |
||||
setActionCache.remove(sequence); |
||||
String logs = getActionStr(tagAliasBean.action) |
||||
+ " tag " |
||||
+ jPushMessage.getCheckTag() |
||||
+ " bind state success,state:" |
||||
+ jPushMessage.getTagCheckStateResult(); |
||||
Timber.w(TAG, logs); |
||||
} else { |
||||
String logs = "Failed to " |
||||
+ getActionStr(tagAliasBean.action) |
||||
+ " tags, errorCode:" |
||||
+ jPushMessage.getErrorCode(); |
||||
Timber.w(TAG, logs); |
||||
if (RetryActionIfNeeded(jPushMessage.getErrorCode(), tagAliasBean)) { |
||||
Timber.w(TAG, logs); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void onAliasOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
int sequence = jPushMessage.getSequence(); |
||||
Timber.i(TAG, "action - onAliasOperatorResult, sequence:" |
||||
+ sequence |
||||
+ ",alias:" |
||||
+ jPushMessage.getAlias()); |
||||
|
||||
init(context); |
||||
|
||||
// 根据sequence从之前操作缓存中获取缓存记录
|
||||
TagAliasBean tagAliasBean = (TagAliasBean) setActionCache.get(sequence); |
||||
if (tagAliasBean == null) { |
||||
Timber.w(TAG, "获取缓存记录失败"); |
||||
return; |
||||
} |
||||
if (jPushMessage.getErrorCode() == 0) { |
||||
Timber.i(TAG, "action - modify alias Success,sequence:" + sequence); |
||||
setActionCache.remove(sequence); |
||||
String logs = getActionStr(tagAliasBean.action) + " alias success"; |
||||
Timber.w(TAG, logs); |
||||
} else { |
||||
String logs = "Failed to " |
||||
+ getActionStr(tagAliasBean.action) |
||||
+ " alias, errorCode:" |
||||
+ jPushMessage.getErrorCode(); |
||||
Timber.w(TAG, logs); |
||||
if (RetryActionIfNeeded(jPushMessage.getErrorCode(), tagAliasBean)) { |
||||
Timber.w(TAG, logs); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 设置手机号码回调 |
||||
*/ |
||||
void onMobileNumberOperatorResult(Context context, JPushMessage jPushMessage) { |
||||
int sequence = jPushMessage.getSequence(); |
||||
Timber.i(TAG, "action - onMobileNumberOperatorResult, sequence:" |
||||
+ sequence |
||||
+ ",mobileNumber:" |
||||
+ jPushMessage.getMobileNumber()); |
||||
|
||||
init(context); |
||||
|
||||
if (jPushMessage.getErrorCode() == 0) { |
||||
Timber.i(TAG, "action - set mobile number Success,sequence:" + sequence); |
||||
setActionCache.remove(sequence); |
||||
} else { |
||||
String logs = "Failed to set mobile number, errorCode:" + jPushMessage.getErrorCode(); |
||||
Timber.e(TAG, logs); |
||||
if (!RetrySetMObileNumberActionIfNeeded(jPushMessage.getErrorCode(), |
||||
jPushMessage.getMobileNumber())) { |
||||
Timber.w(TAG, logs); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static class TagAliasBean { |
||||
|
||||
int action; |
||||
Set<String> tags; |
||||
String alias; |
||||
boolean isAliasAction; |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "TagAliasBean{" |
||||
+ "action=" |
||||
+ action |
||||
+ ", tags=" |
||||
+ tags |
||||
+ ", alias='" |
||||
+ alias |
||||
+ '\'' |
||||
+ ", isAliasAction=" |
||||
+ isAliasAction |
||||
+ '}'; |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,7 +0,0 @@ |
||||
package com.android.sdk.push.mipush; |
||||
|
||||
import com.android.sdk.push.Push; |
||||
|
||||
|
||||
public abstract class MiPush implements Push { |
||||
} |
@ -1,22 +0,0 @@ |
||||
*.iml |
||||
.gradle |
||||
/local.properties |
||||
/.idea |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
.externalNativeBuild |
||||
*.iml |
||||
.idea/ |
||||
.gradle |
||||
/local.properties |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
*.apk |
||||
*.ap_ |
||||
*.dex |
||||
*.class |
||||
bin/ |
||||
gen/ |
||||
local.properties |
@ -1,84 +0,0 @@ |
||||
# 说明 |
||||
|
||||
## 微信登录 |
||||
|
||||
微信登录需要在`包名.wxapi` 包中添加一个名为 `WXEntryActivity` 的 Activity,并继承该 module 提供的 `AbsWXEntryActivity`。 |
||||
|
||||
```java |
||||
/** |
||||
* 微信分享、登录回调 |
||||
* |
||||
* @author Ztiany |
||||
*/ |
||||
@SuppressWarnings("all") |
||||
public class WXEntryActivity extends AbsWXEntryActivity { |
||||
|
||||
|
||||
} |
||||
``` |
||||
|
||||
manifest 配置参考 |
||||
|
||||
```xml |
||||
<!--微信分享回调--> |
||||
<activity |
||||
android:name="应用包名.wxapi.WXEntryActivity" |
||||
android:exported="true" |
||||
android:screenOrientation="portrait"/> |
||||
``` |
||||
|
||||
## 微信支付 |
||||
|
||||
微信支付需要在`包名.wxapi` 包中添加一个名为 `WXPayEntryActivity` 的 Activity,并继承该 module 提供的 `AbsWeChatPayEntryActivity`。 |
||||
|
||||
```java |
||||
/** |
||||
* 微信分享、登录回调 |
||||
* |
||||
* @author Ztiany |
||||
*/ |
||||
@SuppressWarnings("all") |
||||
public class WXPayEntryActivity extends AbsWeChatPayEntryActivity { |
||||
|
||||
} |
||||
``` |
||||
|
||||
manifest 配置参考 |
||||
|
||||
```xml |
||||
<!--微信分享回调--> |
||||
<activity |
||||
android:name="应用包名.wxapi.WXPayEntryActivity" |
||||
android:exported="true" |
||||
android:screenOrientation="portrait"/> |
||||
``` |
||||
|
||||
## 支付宝支付 |
||||
|
||||
- sdk 版本:alipaySdk-15.6.2-20190416165100-noUtdid |
||||
|
||||
## QQ |
||||
|
||||
manifest 配置参考 |
||||
|
||||
```xml |
||||
<activity |
||||
android:name="com.tencent.tauth.AuthActivity" |
||||
android:launchMode="singleTask" |
||||
android:noHistory="true"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.VIEW"/> |
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/> |
||||
<category android:name="android.intent.category.BROWSABLE"/> |
||||
|
||||
<!--1101491530 为你得 AppId--> |
||||
<data android:scheme="tencent1101491530"/> |
||||
</intent-filter> |
||||
</activity> |
||||
|
||||
<activity |
||||
android:name="com.tencent.connect.common.AssistActivity" |
||||
android:configChanges="orientation|keyboardHidden|screenSize" |
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"/> |
||||
``` |
@ -1,50 +0,0 @@ |
||||
apply plugin: 'com.android.library' |
||||
|
||||
android { |
||||
|
||||
compileSdkVersion rootProject.compileSdkVersion |
||||
buildToolsVersion rootProject.buildToolsVersion |
||||
|
||||
defaultConfig { |
||||
minSdkVersion rootProject.minSdkVersion |
||||
targetSdkVersion rootProject.targetSdkVersion |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
} |
||||
|
||||
buildTypes { |
||||
release { |
||||
minifyEnabled false |
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
|
||||
lintOptions { |
||||
abortOnError false |
||||
} |
||||
|
||||
compileOptions { |
||||
sourceCompatibility JavaVersion.VERSION_1_8 |
||||
targetCompatibility JavaVersion.VERSION_1_8 |
||||
} |
||||
|
||||
} |
||||
|
||||
dependencies { |
||||
api fileTree(dir: 'libs', include: ['*.jar', '*.aar']) |
||||
implementation androidLibraries.lifecycleExtensions |
||||
implementation androidLibraries.androidCompatV4 |
||||
implementation androidLibraries.androidCompatV7 |
||||
implementation androidLibraries.androidAnnotations |
||||
implementation androidLibraries.lifecycle |
||||
implementation androidLibraries.lifecycleJava8 |
||||
implementation androidLibraries.lifecycleExtensions |
||||
implementation thirdLibraries.rxJava |
||||
implementation thirdLibraries.retrofit |
||||
implementation thirdLibraries.retrofitConverterGson |
||||
implementation thirdLibraries.okHttp |
||||
implementation thirdLibraries.gson |
||||
implementation thirdLibraries.retrofitRxJava2CallAdapter |
||||
implementation thirdLibraries.timber |
||||
api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.1.6' |
||||
} |
Binary file not shown.
Binary file not shown.
@ -1,21 +0,0 @@ |
||||
# Add project specific ProGuard rules here. |
||||
# You can control the set of applied configuration files using the |
||||
# proguardFiles setting in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# 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 |
@ -1,21 +0,0 @@ |
||||
<manifest package="com.android.sdk.social" |
||||
xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
||||
<application> |
||||
|
||||
<!-- 支付宝支付 start--> |
||||
<activity |
||||
android:name="com.alipay.sdk.app.H5PayActivity" |
||||
android:configChanges="orientation|keyboardHidden|navigation" |
||||
android:exported="false" |
||||
android:screenOrientation="behind"/> |
||||
<activity |
||||
android:name="com.alipay.sdk.auth.AuthActivity" |
||||
android:configChanges="orientation|keyboardHidden|navigation" |
||||
android:exported="false" |
||||
android:screenOrientation="behind"/> |
||||
<!-- 支付宝支付 end--> |
||||
|
||||
</application> |
||||
|
||||
</manifest> |
@ -1,132 +0,0 @@ |
||||
package com.android.sdk.social.ali; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.ComponentName; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.net.Uri; |
||||
import android.text.TextUtils; |
||||
|
||||
import com.alipay.sdk.app.PayTask; |
||||
|
||||
import org.reactivestreams.Subscriber; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import io.reactivex.Observable; |
||||
import io.reactivex.ObservableEmitter; |
||||
import io.reactivex.functions.Consumer; |
||||
|
||||
/** |
||||
* 支付宝支付执行器 |
||||
* <pre> |
||||
* 支付宝SDK版本:2016.01.20 |
||||
* </pre> |
||||
* |
||||
* @author Ztiany |
||||
*/ |
||||
public class AliPayExecutor { |
||||
|
||||
private static final int PAY_RESULT_SUCCESS = 1; |
||||
private static final int PAY_RESULT_CANCEL = 2; |
||||
private static final int PAY_RESULT_FAIL = 3; |
||||
private static final int PAY_RESULT_WAIT_CONFIRM = 4; |
||||
|
||||
public static Observable<AliPayResult> doAliPay(final Activity activity, final String sign) { |
||||
return Observable.create( |
||||
(ObservableEmitter<AliPayResult> subscriber) -> { |
||||
if (subscriber.isDisposed()) { |
||||
return; |
||||
} |
||||
try { |
||||
PayTask payTask = new PayTask(activity); |
||||
Map<String, String> pay = payTask.payV2(sign, false);//不要出现丑陋AliPay对话框-_-!
|
||||
subscriber.onNext(new AliPayResult(pay)); |
||||
subscriber.onComplete(); |
||||
} catch (Exception e) { |
||||
subscriber.onError(e); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 检测是否安装支付宝 |
||||
*/ |
||||
public static boolean isAliPayInstalled(Context context) { |
||||
Uri uri = Uri.parse("alipays://platformapi/startApp"); |
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri); |
||||
ComponentName componentName = intent.resolveActivity(context.getPackageManager()); |
||||
return componentName != null; |
||||
} |
||||
|
||||
/** |
||||
* 同步返回的结果必须放置到服务端进行验证(验证的规则请看https://doc.open.alipay.com/doc2/
|
||||
* detail.htm?spm=0.0.0.0.xdvAU6&treeId=59&articleId=103665& |
||||
* docType=1) 建议商户依赖异步通知 |
||||
*/ |
||||
private static Integer parseResult(AliPayResult payResult) { |
||||
//String resultInfo = payResult.getResult();// 同步返回需要验证的信息
|
||||
String resultStatus = payResult.getResultStatus(); |
||||
// 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档
|
||||
if (TextUtils.equals(resultStatus, "9000")) { |
||||
return PAY_RESULT_SUCCESS; |
||||
} else { |
||||
// 判断resultStatus 为非"9000"则代表可能支付失败
|
||||
// "8000"代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)
|
||||
if (TextUtils.equals(resultStatus, "8000")) { |
||||
//Toast.makeText(PayDemoActivity.this, "支付结果确认中", Toast.LENGTH_SHORT).show();
|
||||
return PAY_RESULT_WAIT_CONFIRM; |
||||
} else if (TextUtils.equals(resultStatus, "6001")) { |
||||
return PAY_RESULT_CANCEL; |
||||
} else { |
||||
// 其他值就可以判断为支付失败,或者系统返回的错误
|
||||
return PAY_RESULT_FAIL; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static class PayConsumer implements Consumer<AliPayResult> { |
||||
PayResultCallback payResultCallback; |
||||
|
||||
public PayConsumer(PayResultCallback payResultCallback) { |
||||
this.payResultCallback = payResultCallback; |
||||
} |
||||
|
||||
@Override |
||||
public void accept(AliPayResult aliPayResult) { |
||||
int result = parseResult(aliPayResult); |
||||
if (result == PAY_RESULT_CANCEL) { |
||||
payResultCallback.onPayCancel(); |
||||
} else if (result == PAY_RESULT_FAIL) { |
||||
payResultCallback.onPayFail(aliPayResult.getMemo()); |
||||
} else if (result == PAY_RESULT_SUCCESS) { |
||||
payResultCallback.onPaySuccess(); |
||||
} else if (result == PAY_RESULT_WAIT_CONFIRM) { |
||||
payResultCallback.onPayNeedConfirmResult(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@SuppressWarnings("unused") |
||||
public abstract static class PaySubscriber implements PayResultCallback, Subscriber<AliPayResult> { |
||||
|
||||
@Override |
||||
public void onComplete() { |
||||
} |
||||
|
||||
@Override |
||||
public final void onNext(AliPayResult aliPayResult) { |
||||
int result = parseResult(aliPayResult); |
||||
if (result == PAY_RESULT_CANCEL) { |
||||
onPayCancel(); |
||||
} else if (result == PAY_RESULT_FAIL) { |
||||
onPayFail(aliPayResult.getMemo()); |
||||
} else if (result == PAY_RESULT_SUCCESS) { |
||||
onPaySuccess(); |
||||
} else if (result == PAY_RESULT_WAIT_CONFIRM) { |
||||
onPayNeedConfirmResult(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,85 +0,0 @@ |
||||
package com.android.sdk.social.ali; |
||||
|
||||
import android.support.annotation.NonNull; |
||||
import android.text.TextUtils; |
||||
|
||||
import java.util.Map; |
||||
|
||||
@SuppressWarnings("unused,WeakerAccess") |
||||
public class AliPayResult { |
||||
|
||||
private String resultStatus; |
||||
private String result; |
||||
private String memo; |
||||
|
||||
AliPayResult(String rawResult) { |
||||
|
||||
if (TextUtils.isEmpty(rawResult)) { |
||||
return; |
||||
} |
||||
|
||||
String[] resultParams = rawResult.split(";"); |
||||
for (String resultParam : resultParams) { |
||||
if (resultParam.startsWith("resultStatus")) { |
||||
resultStatus = gatValue(resultParam, "resultStatus"); |
||||
} |
||||
if (resultParam.startsWith("result")) { |
||||
result = gatValue(resultParam, "result"); |
||||
} |
||||
if (resultParam.startsWith("memo")) { |
||||
memo = gatValue(resultParam, "memo"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
AliPayResult(Map<String, String> rawResult) { |
||||
|
||||
if (rawResult == null) { |
||||
return; |
||||
} |
||||
for (String key : rawResult.keySet()) { |
||||
if (TextUtils.equals(key, "resultStatus")) { |
||||
resultStatus = rawResult.get(key); |
||||
} else if (TextUtils.equals(key, "result")) { |
||||
result = rawResult.get(key); |
||||
} else if (TextUtils.equals(key, "memo")) { |
||||
memo = rawResult.get(key); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "resultStatus={" + resultStatus + "};memo={" + memo |
||||
+ "};result={" + result + "}"; |
||||
} |
||||
|
||||
private String gatValue(String content, String key) { |
||||
String prefix = key + "={"; |
||||
return content.substring(content.indexOf(prefix) + prefix.length(), |
||||
content.lastIndexOf("}")); |
||||
} |
||||
|
||||
/** |
||||
* @return the resultStatus |
||||
*/ |
||||
String getResultStatus() { |
||||
return resultStatus; |
||||
} |
||||
|
||||
/** |
||||
* @return the memo |
||||
*/ |
||||
public String getMemo() { |
||||
return memo; |
||||
} |
||||
|
||||
/** |
||||
* @return the result |
||||
*/ |
||||
public String getResult() { |
||||
return result; |
||||
} |
||||
|
||||
} |
@ -1,14 +0,0 @@ |
||||
package com.android.sdk.social.ali; |
||||
|
||||
|
||||
public interface PayResultCallback { |
||||
|
||||
void onPayCancel(); |
||||
|
||||
void onPayFail(String errStr); |
||||
|
||||
void onPaySuccess(); |
||||
|
||||
void onPayNeedConfirmResult(); |
||||
|
||||
} |
@ -1,97 +0,0 @@ |
||||
package com.android.sdk.social.common; |
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2018-11-07 17:42 |
||||
*/ |
||||
@SuppressWarnings("WeakerAccess,unused") |
||||
public class Status<T> { |
||||
|
||||
public static final int STATE_SUCCESS = 0; |
||||
public static final int STATE_FAILED = 1; |
||||
public static final int STATE_CANCEL = 2; |
||||
public static final int STATE_REQUESTING = 3; |
||||
|
||||
private final T result; |
||||
private final Throwable t; |
||||
private final int status; |
||||
|
||||
private Status(T result, Throwable t, int status) { |
||||
this.result = result; |
||||
this.t = t; |
||||
this.status = status; |
||||
} |
||||
|
||||
public int getStatus() { |
||||
return status; |
||||
} |
||||
|
||||
public boolean isRequesting() { |
||||
return status == STATE_REQUESTING; |
||||
} |
||||
|
||||
public boolean isError() { |
||||
return status == STATE_FAILED; |
||||
} |
||||
|
||||
public boolean isSuccess() { |
||||
return status == STATE_SUCCESS; |
||||
} |
||||
|
||||
public boolean isCancel() { |
||||
return status == STATE_CANCEL; |
||||
} |
||||
|
||||
public boolean hasData() { |
||||
return result != null; |
||||
} |
||||
|
||||
public T getResult() { |
||||
return result; |
||||
} |
||||
|
||||
public T getResultOrElse(T whenNull) { |
||||
if (result == null) { |
||||
return whenNull; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public Throwable getError() { |
||||
return t; |
||||
} |
||||
|
||||
public static <T> Status<T> success(T t) { |
||||
return new Status<>(t, null, STATE_SUCCESS); |
||||
} |
||||
|
||||
public static <T> Status<T> success() { |
||||
return new Status<>(null, null, STATE_SUCCESS); |
||||
} |
||||
|
||||
public static <T> Status<T> error(Throwable throwable) { |
||||
return new Status<>(null, throwable, STATE_FAILED); |
||||
} |
||||
|
||||
public static <T> Status<T> loading() { |
||||
return new Status<>(null, null, STATE_REQUESTING); |
||||
} |
||||
|
||||
public static <T> Status<T> cancel() { |
||||
return new Status<>(null, null, STATE_CANCEL); |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "Status{" + |
||||
"result=" + result + |
||||
", t=" + t + |
||||
", status=" + status + |
||||
'}'; |
||||
} |
||||
|
||||
} |
@ -1,17 +0,0 @@ |
||||
package com.android.sdk.social.common; |
||||
|
||||
import android.text.TextUtils; |
||||
|
||||
|
||||
public class Utils { |
||||
|
||||
private Utils() { |
||||
} |
||||
|
||||
public static void requestNotNull(String str, String errorMsg) { |
||||
if (TextUtils.isEmpty(str)) { |
||||
throw new NullPointerException(errorMsg); |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,76 +0,0 @@ |
||||
package com.android.sdk.social.qq; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.support.annotation.Nullable; |
||||
|
||||
import com.android.sdk.social.common.Utils; |
||||
import com.tencent.tauth.IUiListener; |
||||
import com.tencent.tauth.Tencent; |
||||
import com.tencent.tauth.UiError; |
||||
|
||||
import timber.log.Timber; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2019-08-27 18:16 |
||||
*/ |
||||
public class QQManager { |
||||
|
||||
private final Tencent mTencent; |
||||
|
||||
private static String sAppId; |
||||
|
||||
public static void initQQSDK(String appId) { |
||||
sAppId = appId; |
||||
} |
||||
|
||||
private static String getAppId() { |
||||
Utils.requestNotNull(sAppId, "weChat app id"); |
||||
return sAppId; |
||||
} |
||||
|
||||
public QQManager(Context context) { |
||||
mTencent = Tencent.createInstance(getAppId(), context); |
||||
} |
||||
|
||||
public void shareToQQ(Activity activity, QQShareInfo shareInfo, @Nullable ShareResultCallback shareResultCallback) { |
||||
mTencent.shareToQQ(activity, shareInfo.getBundle(), newDefaultListener(shareResultCallback)); |
||||
} |
||||
|
||||
public boolean isQQInstalled(Context context) { |
||||
return mTencent.isQQInstalled(context); |
||||
} |
||||
|
||||
public static boolean onActivityResult(int requestCode, int resultCode, Intent intent) { |
||||
return Tencent.onActivityResultData(requestCode, resultCode, intent, null); |
||||
} |
||||
|
||||
private static IUiListener newDefaultListener(ShareResultCallback shareResultCallback) { |
||||
if (shareResultCallback == null) { |
||||
return null; |
||||
} |
||||
return new IUiListener() { |
||||
@Override |
||||
public void onComplete(Object o) { |
||||
Timber.d("shareToQQ onComplete: " + o); |
||||
shareResultCallback.onSuccess(); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(UiError uiError) { |
||||
Timber.d("shareToQQ onError: " + uiError); |
||||
shareResultCallback.onError(); |
||||
} |
||||
|
||||
@Override |
||||
public void onCancel() { |
||||
Timber.d("shareToQQ onCancel"); |
||||
shareResultCallback.onCancel(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
} |
@ -1,54 +0,0 @@ |
||||
package com.android.sdk.social.qq; |
||||
|
||||
import android.os.Bundle; |
||||
|
||||
import com.tencent.connect.share.QQShare; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2019-08-27 19:00 |
||||
*/ |
||||
public class QQShareInfo { |
||||
|
||||
private final Bundle mBundle = new Bundle(); |
||||
|
||||
public QQShareInfo() { |
||||
shareToFriend(); |
||||
} |
||||
|
||||
public QQShareInfo setTitle(String title) { |
||||
mBundle.putString(QQShare.SHARE_TO_QQ_TITLE, title); |
||||
return this; |
||||
} |
||||
|
||||
public QQShareInfo setTargetUrl(String targetUrl) { |
||||
mBundle.putString(QQShare.SHARE_TO_QQ_TARGET_URL, targetUrl); |
||||
return this; |
||||
} |
||||
|
||||
public QQShareInfo setSummary(String summary) { |
||||
mBundle.putString(QQShare.SHARE_TO_QQ_SUMMARY, summary); |
||||
return this; |
||||
} |
||||
|
||||
public QQShareInfo setImage(String imageUrl) { |
||||
mBundle.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUrl); |
||||
return this; |
||||
} |
||||
|
||||
public QQShareInfo setLocalImage(String imageUrl) { |
||||
mBundle.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, imageUrl); |
||||
return this; |
||||
} |
||||
|
||||
public QQShareInfo shareToFriend() { |
||||
mBundle.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT); |
||||
return this; |
||||
} |
||||
|
||||
Bundle getBundle() { |
||||
return mBundle; |
||||
} |
||||
|
||||
} |
@ -1,16 +0,0 @@ |
||||
package com.android.sdk.social.qq; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2019-08-27 19:35 |
||||
*/ |
||||
public interface ShareResultCallback { |
||||
|
||||
void onSuccess(); |
||||
|
||||
void onError(); |
||||
|
||||
void onCancel(); |
||||
|
||||
} |
@ -1,58 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
|
||||
import com.tencent.mm.opensdk.modelbase.BaseReq; |
||||
import com.tencent.mm.opensdk.modelbase.BaseResp; |
||||
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; |
||||
|
||||
import timber.log.Timber; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2018-11-07 13:51 |
||||
*/ |
||||
public class AbsWXEntryActivity extends Activity implements IWXAPIEventHandler { |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
Timber.d("onCreate() called with: savedInstanceState = [" + savedInstanceState + "]"); |
||||
// 如果分享的时候,该界面没有开启,那么微信开始这个 Activity 时会调用 onCreate,所以这里要处理微信的返回结果。
|
||||
// 注意:第三方开发者如果使用透明界面来实现 WXEntryActivity,则需要判断 handleIntent 的返回值。
|
||||
// 如果返回值为false,则说明入参不合法未被 SDK 处理,应finish当前透明界面,避免外部通过传递非法参数的 Intent 导致停留在透明界面,引起用户的疑惑。
|
||||
boolean result = WeChatManager.handleIntent(getIntent(), this); |
||||
Timber.w("onCreate handleIntent result = " + result); |
||||
} |
||||
|
||||
@Override |
||||
protected void onNewIntent(Intent intent) { |
||||
super.onNewIntent(intent); |
||||
Timber.d("onNewIntent() called with: intent = [" + intent + "]"); |
||||
setIntent(intent); |
||||
boolean result = WeChatManager.handleIntent(intent, this); |
||||
Timber.w("onCreate onNewIntent result = " + result); |
||||
} |
||||
|
||||
/** |
||||
* 微信发送请求到第三方应用时,会回调到该方法 |
||||
*/ |
||||
@Override |
||||
public void onReq(BaseReq baseReq) { |
||||
Timber.d("onReq() called with: baseReq = [" + baseReq + "]"); |
||||
} |
||||
|
||||
/** |
||||
* 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法 |
||||
*/ |
||||
@Override |
||||
public void onResp(BaseResp baseResp) { |
||||
Timber.d("onResp() called with: baseResp = [" + baseResp + "]"); |
||||
WeChatManager.handleOnWxEntryResp(baseResp); |
||||
this.finish(); |
||||
} |
||||
|
||||
} |
@ -1,41 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
|
||||
import com.tencent.mm.opensdk.modelbase.BaseReq; |
||||
import com.tencent.mm.opensdk.modelbase.BaseResp; |
||||
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; |
||||
|
||||
public abstract class AbsWXPayEntryActivity extends Activity implements IWXAPIEventHandler { |
||||
|
||||
@Override |
||||
public void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
WeChatManager.handleIntent(getIntent(), this); |
||||
} |
||||
|
||||
@Override |
||||
protected void onNewIntent(Intent intent) { |
||||
super.onNewIntent(intent); |
||||
setIntent(intent); |
||||
WeChatManager.handleIntent(getIntent(), this); |
||||
} |
||||
|
||||
@Override |
||||
public void onReq(BaseReq baseReq) { |
||||
} |
||||
|
||||
@Override |
||||
public void onResp(BaseResp baseResp) { |
||||
WeChatManager.handleOnWxEntryResp(baseResp); |
||||
this.finish(); |
||||
} |
||||
|
||||
@Override |
||||
protected void onDestroy() { |
||||
super.onDestroy(); |
||||
} |
||||
|
||||
} |
@ -1,32 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2018-11-07 15:17 |
||||
*/ |
||||
@SuppressWarnings("unused") |
||||
public class AuthResult { |
||||
|
||||
private int errcode; |
||||
private String errmsg; |
||||
|
||||
int getErrcode() { |
||||
return errcode; |
||||
} |
||||
|
||||
String getErrmsg() { |
||||
return errmsg; |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "AuthResult{" + |
||||
"errcode=" + errcode + |
||||
", errmsg='" + errmsg + '\'' + |
||||
'}'; |
||||
} |
||||
} |
@ -1,86 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
@SuppressWarnings("unused,WeakerAccess") |
||||
public class PayInfo { |
||||
|
||||
private String mAppId; |
||||
private String mPartnerId; |
||||
private String mPrepayId; |
||||
private String mPackage; |
||||
private String mNonceStr; |
||||
private String mTimestamp; |
||||
private String mSign; |
||||
|
||||
public String getAppId() { |
||||
return mAppId; |
||||
} |
||||
|
||||
public void setAppId(String appId) { |
||||
mAppId = appId; |
||||
} |
||||
|
||||
public String getPartnerId() { |
||||
return mPartnerId; |
||||
} |
||||
|
||||
public void setPartnerId(String partnerId) { |
||||
mPartnerId = partnerId; |
||||
} |
||||
|
||||
public String getPrepayId() { |
||||
return mPrepayId; |
||||
} |
||||
|
||||
public void setPrepayId(String prepayId) { |
||||
mPrepayId = prepayId; |
||||
} |
||||
|
||||
public String getPackage() { |
||||
return mPackage; |
||||
} |
||||
|
||||
public void setPackage(String aPackage) { |
||||
mPackage = aPackage; |
||||
} |
||||
|
||||
public String getNonceStr() { |
||||
return mNonceStr; |
||||
} |
||||
|
||||
public void setNonceStr(String nonceStr) { |
||||
mNonceStr = nonceStr; |
||||
} |
||||
|
||||
public String getTimestamp() { |
||||
return mTimestamp; |
||||
} |
||||
|
||||
public void setTimestamp(String timestamp) { |
||||
mTimestamp = timestamp; |
||||
} |
||||
|
||||
public String getSign() { |
||||
return mSign; |
||||
} |
||||
|
||||
public void setSign(String sign) { |
||||
mSign = sign; |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "PayInfo{" + |
||||
"mAppId='" + mAppId + '\'' + |
||||
", mPartnerId='" + mPartnerId + '\'' + |
||||
", mPrepayId='" + mPrepayId + '\'' + |
||||
", mPackage='" + mPackage + '\'' + |
||||
", mNonceStr='" + mNonceStr + '\'' + |
||||
", mTimestamp='" + mTimestamp + '\'' + |
||||
", mSign='" + mSign + '\'' + |
||||
'}'; |
||||
} |
||||
} |
@ -1,115 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.arch.lifecycle.LifecycleOwner; |
||||
import android.arch.lifecycle.MediatorLiveData; |
||||
import android.arch.lifecycle.Observer; |
||||
import android.support.annotation.NonNull; |
||||
import android.support.annotation.Nullable; |
||||
|
||||
import java.lang.ref.WeakReference; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.ListIterator; |
||||
|
||||
import timber.log.Timber; |
||||
|
||||
public class SingleLiveData<T> extends MediatorLiveData<T> { |
||||
|
||||
private int mVersion = 0; |
||||
|
||||
private final List<WeakReference<ObserverWrapper<T>>> mWrapperObserverList = new ArrayList<>(); |
||||
|
||||
@Override |
||||
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { |
||||
super.observe(owner, getOrNewObserver(observer, mVersion)); |
||||
} |
||||
|
||||
@Override |
||||
public void observeForever(@NonNull Observer<T> observer) { |
||||
super.observeForever(getOrNewObserver(observer, mVersion)); |
||||
} |
||||
|
||||
@Override |
||||
public void setValue(T value) { |
||||
mVersion++; |
||||
super.setValue(value); |
||||
} |
||||
|
||||
@Override |
||||
public void removeObserver(@NonNull Observer<T> observer) { |
||||
if (observer instanceof ObserverWrapper) { |
||||
super.removeObserver(observer); |
||||
removeWrapper((ObserverWrapper) observer); |
||||
Timber.d("removeObserver() called with: observer = wrapper = [" + observer + "]"); |
||||
} else { |
||||
ObserverWrapper<T> wrapper = findWrapper(observer); |
||||
Timber.d("removeObserver() called with: observer = [" + observer + "], wrapper = [" + wrapper + "]"); |
||||
super.removeObserver(wrapper); |
||||
removeWrapper(wrapper); |
||||
} |
||||
} |
||||
|
||||
private void removeWrapper(ObserverWrapper observer) { |
||||
ListIterator<WeakReference<ObserverWrapper<T>>> iterator = mWrapperObserverList.listIterator(); |
||||
while (iterator.hasNext()) { |
||||
WeakReference<ObserverWrapper<T>> next = iterator.next(); |
||||
ObserverWrapper<T> item = next.get(); |
||||
if (item == observer) { |
||||
iterator.remove(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private ObserverWrapper<T> findWrapper(Observer<T> observer) { |
||||
ListIterator<WeakReference<ObserverWrapper<T>>> iterator = mWrapperObserverList.listIterator(); |
||||
|
||||
ObserverWrapper<T> target = null; |
||||
|
||||
while (iterator.hasNext()) { |
||||
WeakReference<ObserverWrapper<T>> next = iterator.next(); |
||||
ObserverWrapper<T> item = next.get(); |
||||
if (item == null) { |
||||
iterator.remove(); |
||||
} else if (item.mOrigin == observer) { |
||||
target = item; |
||||
} |
||||
} |
||||
|
||||
return target; |
||||
} |
||||
|
||||
private Observer<T> getOrNewObserver(@NonNull Observer<T> observer, int observerVersion) { |
||||
ObserverWrapper<T> wrapper = findWrapper(observer); |
||||
|
||||
if (wrapper == null) { |
||||
wrapper = new ObserverWrapper<>(observerVersion, observer); |
||||
mWrapperObserverList.add(new WeakReference<>(wrapper)); |
||||
} |
||||
|
||||
Timber.d("getOrNewObserver() called with: observer = [" + observer + "], observerVersion = [" + observerVersion + "], wrapper = [" + wrapper + "]"); |
||||
|
||||
return wrapper; |
||||
} |
||||
|
||||
private class ObserverWrapper<E> implements Observer<E> { |
||||
|
||||
private final int mObserverVersion; |
||||
|
||||
private final Observer<E> mOrigin; |
||||
|
||||
private ObserverWrapper(int observerVersion, Observer<E> origin) { |
||||
mObserverVersion = observerVersion; |
||||
mOrigin = origin; |
||||
} |
||||
|
||||
@Override |
||||
public void onChanged(@Nullable E t) { |
||||
if (mObserverVersion < mVersion && mOrigin != null) { |
||||
mOrigin.onChanged(t); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -1,45 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import io.reactivex.Observable; |
||||
import io.reactivex.schedulers.Schedulers; |
||||
import retrofit2.Retrofit; |
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; |
||||
import retrofit2.converter.gson.GsonConverterFactory; |
||||
import retrofit2.http.GET; |
||||
import retrofit2.http.Query; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2018-11-07 14:50 |
||||
*/ |
||||
class WXApiFactory { |
||||
|
||||
static ServiceApi createWXApi() { |
||||
Retrofit retrofit = new Retrofit.Builder() |
||||
.baseUrl("https://api.weixin.qq.com/sns/") |
||||
.addConverterFactory(GsonConverterFactory.create()) |
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) |
||||
.build(); |
||||
|
||||
return retrofit.create(ServiceApi.class); |
||||
} |
||||
|
||||
interface ServiceApi { |
||||
|
||||
//获取openid、accessToken值用于后期操作
|
||||
@GET("oauth2/access_token") |
||||
Observable<WXToken> getAccessToken(@Query("appid") String appId, @Query("secret") String appSecret, @Query("code") String code, @Query("grant_type") String granType); |
||||
|
||||
//检验授权凭证(access_token)是否有效
|
||||
@GET("auth") |
||||
Observable<AuthResult> validateToken(@Query("access_token") String access_token, @Query("openid") String openid); |
||||
|
||||
//获取用户个人信息
|
||||
@GET("userinfo") |
||||
Observable<WXUser> getWeChatUser(@Query("access_token") String access_token, @Query("openid") String openid); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
@ -1,40 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
@SuppressWarnings("unused") |
||||
class WXToken extends AuthResult { |
||||
|
||||
private String access_token; |
||||
private String expires_in; |
||||
private String refresh_token; |
||||
private String openid; |
||||
private String scope; |
||||
private String unionid; |
||||
|
||||
String getAccess_token() { |
||||
return access_token; |
||||
} |
||||
|
||||
public String getRefresh_token() { |
||||
return refresh_token; |
||||
} |
||||
|
||||
String getOpenid() { |
||||
return openid; |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "WXToken{" + |
||||
"access_token='" + access_token + '\'' + |
||||
", expires_in='" + expires_in + '\'' + |
||||
", refresh_token='" + refresh_token + '\'' + |
||||
", openid='" + openid + '\'' + |
||||
", scope='" + scope + '\'' + |
||||
", unionid='" + unionid + '\'' + |
||||
'}'; |
||||
} |
||||
|
||||
} |
@ -1,92 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
import java.util.List; |
||||
|
||||
@SuppressWarnings("unused") |
||||
public class WXUser extends AuthResult { |
||||
|
||||
/** |
||||
* 普通用户的标识,对当前开发者帐号唯一 |
||||
*/ |
||||
private String openid; |
||||
|
||||
private String nickname; |
||||
|
||||
/** |
||||
* 普通用户性别,1为男性,2为女性 |
||||
*/ |
||||
private int sex; |
||||
|
||||
private String province; |
||||
private String city; |
||||
private String country; |
||||
|
||||
/** |
||||
* 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 |
||||
*/ |
||||
private String headimgurl; |
||||
|
||||
/** |
||||
* 开发者最好保存unionID信息,以便以后在不同应用之间进行用户信息互通。 |
||||
*/ |
||||
private String unionid; |
||||
|
||||
private List<String> privilege; |
||||
|
||||
public String getOpenid() { |
||||
return openid; |
||||
} |
||||
|
||||
public String getNickname() { |
||||
return nickname; |
||||
} |
||||
|
||||
public int getSex() { |
||||
return sex; |
||||
} |
||||
|
||||
public String getProvince() { |
||||
return province; |
||||
} |
||||
|
||||
public String getCity() { |
||||
return city; |
||||
} |
||||
|
||||
public String getCountry() { |
||||
return country; |
||||
} |
||||
|
||||
public String getHeadimgurl() { |
||||
return headimgurl; |
||||
} |
||||
|
||||
public String getUnionid() { |
||||
return unionid; |
||||
} |
||||
|
||||
public List<String> getPrivilege() { |
||||
return privilege; |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return "WXUser{" + |
||||
"openid='" + openid + '\'' + |
||||
", nickname='" + nickname + '\'' + |
||||
", sex=" + sex + |
||||
", province='" + province + '\'' + |
||||
", city='" + city + '\'' + |
||||
", country='" + country + '\'' + |
||||
", headimgurl='" + headimgurl + '\'' + |
||||
", unionid='" + unionid + '\'' + |
||||
", privilege=" + privilege + |
||||
", errcode=" + getErrcode() + |
||||
", errmsg=" + getErrmsg() + |
||||
'}'; |
||||
} |
||||
|
||||
} |
@ -1,56 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
import com.tencent.mm.opensdk.modelbase.BaseResp; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2018-11-07 17:35 |
||||
*/ |
||||
class WeChatLoginException extends Exception { |
||||
|
||||
private int mErrorCode; |
||||
private String mErrMsg; |
||||
|
||||
WeChatLoginException(int errorCode, String errMsg) { |
||||
mErrorCode = errorCode; |
||||
mErrMsg = errMsg; |
||||
} |
||||
|
||||
@Override |
||||
public String getMessage() { |
||||
return getMessageFormBaseResp(); |
||||
} |
||||
|
||||
@NonNull |
||||
@Override |
||||
public String toString() { |
||||
return getMessageFormBaseResp() + "---" + super.toString(); |
||||
} |
||||
|
||||
private String getMessageFormBaseResp() { |
||||
String message = "未知错误"; |
||||
|
||||
switch (mErrorCode) { |
||||
case BaseResp.ErrCode.ERR_USER_CANCEL: |
||||
message = "发送取消"; |
||||
break; |
||||
case BaseResp.ErrCode.ERR_SENT_FAILED: |
||||
message = "发送失败"; |
||||
break; |
||||
case BaseResp.ErrCode.ERR_AUTH_DENIED: |
||||
message = "发送被拒绝"; |
||||
break; |
||||
case BaseResp.ErrCode.ERR_UNSUPPORT: |
||||
message = "不支持错误"; |
||||
break; |
||||
case BaseResp.ErrCode.ERR_COMM: |
||||
message = "一般错误"; |
||||
break; |
||||
} |
||||
return message + " errMsg = " + mErrMsg; |
||||
} |
||||
|
||||
} |
@ -1,24 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
|
||||
import com.tencent.mm.opensdk.modelmsg.SendAuth; |
||||
|
||||
import io.reactivex.Observable; |
||||
import io.reactivex.ObservableSource; |
||||
import io.reactivex.functions.Function; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2018-11-07 14:36 |
||||
*/ |
||||
class WeChatLoginImpl { |
||||
|
||||
static Observable<WXUser> doWeChatLogin(SendAuth.Resp resp) { |
||||
final WXApiFactory.ServiceApi serviceApi = WXApiFactory.createWXApi(); |
||||
return serviceApi |
||||
.getAccessToken(WeChatManager.getAppId(), WeChatManager.getAppSecret(), resp.code, "authorization_code"/*固定参数*/) |
||||
.flatMap((Function<WXToken, ObservableSource<WXUser>>) wxToken -> serviceApi.getWeChatUser(wxToken.getAccess_token(), wxToken.getOpenid())); |
||||
} |
||||
|
||||
} |
@ -1,333 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.arch.lifecycle.LiveData; |
||||
import android.arch.lifecycle.MutableLiveData; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.support.annotation.NonNull; |
||||
import android.text.TextUtils; |
||||
|
||||
import com.android.sdk.social.common.Status; |
||||
import com.android.sdk.social.common.Utils; |
||||
import com.tencent.mm.opensdk.constants.ConstantsAPI; |
||||
import com.tencent.mm.opensdk.modelbase.BaseResp; |
||||
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram; |
||||
import com.tencent.mm.opensdk.modelmsg.SendAuth; |
||||
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX; |
||||
import com.tencent.mm.opensdk.modelpay.PayReq; |
||||
import com.tencent.mm.opensdk.openapi.IWXAPI; |
||||
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; |
||||
import com.tencent.mm.opensdk.openapi.WXAPIFactory; |
||||
|
||||
import timber.log.Timber; |
||||
|
||||
|
||||
@SuppressWarnings("unused") |
||||
public class WeChatManager { |
||||
|
||||
private static WeChatManager sWeChatManager; |
||||
private final IWXAPI mWxApi; |
||||
|
||||
private static String sAppId; |
||||
private static String sAppSecret; |
||||
|
||||
/** |
||||
* @param context 上下文 |
||||
* @param appId app id |
||||
* @param appSecret 密钥,如果要进行微信登录,则需要提供。 |
||||
*/ |
||||
public static synchronized void initWeChatSDK(Context context, String appId, String appSecret) { |
||||
if (sWeChatManager != null) { |
||||
throw new UnsupportedOperationException("WeChatManager has already been initialized"); |
||||
} |
||||
sAppId = appId; |
||||
sAppSecret = appSecret; |
||||
sWeChatManager = new WeChatManager(context); |
||||
} |
||||
|
||||
private static synchronized void destroy() { |
||||
sWeChatManager.currentState = null; |
||||
sWeChatManager.mWxApi.unregisterApp(); |
||||
sWeChatManager.mWxApi.detach(); |
||||
sWeChatManager = null; |
||||
} |
||||
|
||||
static String getAppId() { |
||||
Utils.requestNotNull(sAppId, "weChat app id"); |
||||
return sAppId; |
||||
} |
||||
|
||||
static String getAppSecret() { |
||||
Utils.requestNotNull(sAppSecret, "weChat appSecret"); |
||||
return sAppSecret; |
||||
} |
||||
|
||||
private WeChatManager(Context context) { |
||||
mWxApi = WXAPIFactory.createWXAPI(context.getApplicationContext(), getAppId(), false); |
||||
mWxApi.registerApp(getAppId()); |
||||
sWeChatManager = this; |
||||
} |
||||
|
||||
public static synchronized WeChatManager getInstance() { |
||||
if (sWeChatManager == null) { |
||||
throw new UnsupportedOperationException("WeChatManager has not been initialized"); |
||||
} |
||||
return sWeChatManager; |
||||
} |
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 通用
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static boolean handleIntent(Intent intent, IWXAPIEventHandler iwxapiEventHandler) { |
||||
WeChatManager weChatManager = sWeChatManager; |
||||
if (weChatManager != null) { |
||||
return weChatManager.mWxApi.handleIntent(intent, iwxapiEventHandler); |
||||
} else { |
||||
Timber.w("WeChatManager handleIntent called, but WeChatManager has not been initialized"); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@SuppressWarnings("unused") |
||||
public boolean isInstalledWeChat() { |
||||
return mWxApi.isWXAppInstalled(); |
||||
} |
||||
|
||||
static void handleOnWxEntryResp(BaseResp baseResp) { |
||||
Timber.d("handleOnWxEntryResp type = " + baseResp.getType() + "errStr = " + baseResp.errStr); |
||||
if (ConstantsAPI.COMMAND_SENDAUTH == baseResp.getType()) { |
||||
handAuthResp(baseResp); |
||||
} else if (ConstantsAPI.COMMAND_PAY_BY_WX == baseResp.getType()) { |
||||
handleOnWxEntryPayResp(baseResp); |
||||
} else if (ConstantsAPI.COMMAND_LAUNCH_WX_MINIPROGRAM == baseResp.getType()) { |
||||
handleMiniProgramResp(baseResp); |
||||
} else if (ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX == baseResp.getType()) { |
||||
handleSendMessageResp(baseResp); |
||||
} |
||||
} |
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 小程序
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** |
||||
* 跳转小程序 |
||||
* |
||||
* @param userName 小程序原始id |
||||
* @param path 拉起小程序页面的可带参路径,不填默认拉起小程序首页 |
||||
*/ |
||||
public void navToMinProgram(String userName, String path, boolean isRelease) { |
||||
WXLaunchMiniProgram.Req req = new WXLaunchMiniProgram.Req(); |
||||
req.userName = userName; |
||||
req.path = path; |
||||
// 可选打开开发版,体验版和正式版
|
||||
req.miniprogramType = isRelease ? WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE : WXLaunchMiniProgram.Req.MINIPROGRAM_TYPE_PREVIEW; |
||||
mWxApi.sendReq(req); |
||||
} |
||||
|
||||
private static void handleMiniProgramResp(BaseResp baseResp) { |
||||
if (baseResp instanceof WXLaunchMiniProgram.Resp) { |
||||
WXLaunchMiniProgram.Resp launchMiniProResp = (WXLaunchMiniProgram.Resp) baseResp; |
||||
//对应小程序组件 <button open-type="launchApp"> 中的 app-parameter 属性
|
||||
String extMsg = launchMiniProResp.extMsg; |
||||
Timber.d("handleMiniProgramResp = " + baseResp.errStr); |
||||
} |
||||
} |
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 登录与认证
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private static void handAuthResp(BaseResp baseResp) { |
||||
WeChatManager weChatManager = sWeChatManager; |
||||
|
||||
if (weChatManager == null || !(baseResp instanceof SendAuth.Resp)) { |
||||
return; |
||||
} |
||||
|
||||
SendAuth.Resp resp = (SendAuth.Resp) baseResp; |
||||
|
||||
if (BaseResp.ErrCode.ERR_OK == resp.errCode) { |
||||
Timber.i("WeChatManager handleOnResp success, resp = " + resp); |
||||
if (resp.state.equals(weChatManager.currentState)) { |
||||
weChatManager.handWeChatLoginResp(resp); |
||||
} else { |
||||
Timber.w("WeChatManager handleChatLoginResp called, but state is not matched"); |
||||
} |
||||
} else { |
||||
Timber.w("WeChatManager handleOnResp fail, resp = " + resp); |
||||
int requestType = weChatManager.mRequestType; |
||||
if (requestType == REQUEST_TYPE_CODE) { |
||||
weChatManager.mAuthCode.postValue(Status.error(new WeChatLoginException(resp.errCode, resp.errStr))); |
||||
} else if (requestType == REQUEST_TYPE_USER_INFO) { |
||||
weChatManager.mUserInfo.postValue(Status.error(new WeChatLoginException(resp.errCode, resp.errStr))); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private int mRequestType; |
||||
private String currentState; |
||||
|
||||
private static final int REQUEST_TYPE_CODE = 1; |
||||
private static final int REQUEST_TYPE_USER_INFO = 2; |
||||
|
||||
private final MutableLiveData<Status<WXUser>> mUserInfo = new SingleLiveData<>(); |
||||
private final MutableLiveData<Status<String>> mAuthCode = new SingleLiveData<>(); |
||||
|
||||
/** |
||||
* 默认的state,用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击), |
||||
* 建议第三方带上该参数,可设置为简单的随机数加session进行校验 |
||||
*/ |
||||
private static final String DEFAULT_STATE = "wechat_sdk_login"; |
||||
|
||||
/** |
||||
* 固定的请求域,应用授权作用域,如获取用户个人信息则填写snsapi_userinfo |
||||
*/ |
||||
private static final String GET_USER_INFO_SCOPE = "snsapi_userinfo"; |
||||
|
||||
@NonNull |
||||
@SuppressWarnings("WeakerAccess") |
||||
public LiveData<Status<WXUser>> loginResult() { |
||||
return mUserInfo; |
||||
} |
||||
|
||||
@NonNull |
||||
public LiveData<Status<String>> authResult() { |
||||
return mAuthCode; |
||||
} |
||||
|
||||
/** |
||||
* 请求微信登录,通过 {@link #loginResult() } 获取结果 |
||||
* |
||||
* @param state 第三方程序发送时用来标识其请求的唯一性的标志,由第三方程序调用 sendReq 时传入,由微信终端回传,state 字符串长度不能超过 1K |
||||
*/ |
||||
public void requestChatLogin(String state) { |
||||
mRequestType = REQUEST_TYPE_USER_INFO; |
||||
doRequest(state); |
||||
} |
||||
|
||||
/** |
||||
* 请求获取微信授权码,通过 {@link #authResult()} 获取结果 |
||||
* |
||||
* @param state 第三方程序发送时用来标识其请求的唯一性的标志,由第三方程序调用 sendReq 时传入,由微信终端回传,state 字符串长度不能超过 1K |
||||
*/ |
||||
public void requestAuthCode(String state) { |
||||
mRequestType = REQUEST_TYPE_CODE; |
||||
doRequest(state); |
||||
} |
||||
|
||||
private void doRequest(String state) { |
||||
SendAuth.Req req = new SendAuth.Req(); |
||||
req.scope = GET_USER_INFO_SCOPE; |
||||
req.state = TextUtils.isEmpty(state) ? DEFAULT_STATE : state; |
||||
currentState = req.state; |
||||
mWxApi.sendReq(req); |
||||
} |
||||
|
||||
@SuppressLint("CheckResult") |
||||
private void handWeChatLoginResp(SendAuth.Resp resp) { |
||||
if (mRequestType == REQUEST_TYPE_CODE) { |
||||
|
||||
mAuthCode.postValue(Status.success(resp.code)); |
||||
|
||||
} else if (mRequestType == REQUEST_TYPE_USER_INFO) { |
||||
|
||||
mUserInfo.postValue(Status.loading()); |
||||
Timber.i("handWeChatLoginResp called, requesting user info......."); |
||||
WeChatLoginImpl.doWeChatLogin(resp) |
||||
.subscribe( |
||||
wxUser -> { |
||||
Timber.i("handWeChatLoginResp success and result = " + wxUser); |
||||
processRequestUserInfoResult(wxUser); |
||||
}, |
||||
throwable -> { |
||||
Timber.i("handWeChatLoginResp fail and result = " + throwable); |
||||
mUserInfo.postValue(Status.error(throwable)); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
private void processRequestUserInfoResult(WXUser wxUser) { |
||||
if (wxUser != null) { |
||||
if (wxUser.getErrcode() != 0) { |
||||
mUserInfo.postValue(Status.error(new WeChatLoginException(wxUser.getErrcode(), wxUser.getErrmsg()))); |
||||
} else { |
||||
mUserInfo.postValue(Status.success(wxUser)); |
||||
} |
||||
} else { |
||||
mUserInfo.postValue(Status.error(new WeChatLoginException(BaseResp.ErrCode.ERR_COMM, null))); |
||||
} |
||||
} |
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 支付
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private SingleLiveData<Status> mWXPayResultData = new SingleLiveData<>(); |
||||
|
||||
public void doPay(PayInfo payInfo) { |
||||
PayReq req = new PayReq(); |
||||
req.appId = payInfo.getAppId(); |
||||
req.nonceStr = payInfo.getNonceStr(); |
||||
req.partnerId = payInfo.getPartnerId(); |
||||
req.prepayId = payInfo.getPrepayId(); |
||||
req.packageValue = payInfo.getPackage(); |
||||
req.timeStamp = payInfo.getTimestamp(); |
||||
req.sign = payInfo.getSign(); |
||||
mWxApi.sendReq(req); |
||||
} |
||||
|
||||
public LiveData<Status> getWXPayResultData() { |
||||
return mWXPayResultData; |
||||
} |
||||
|
||||
private static void handleOnWxEntryPayResp(BaseResp baseResp) { |
||||
WeChatManager weChatManager = sWeChatManager; |
||||
if (weChatManager == null) { |
||||
return; |
||||
} |
||||
if (baseResp.errCode == 0) {//成功展示成功页面
|
||||
weChatManager.mWXPayResultData.postValue(Status.success()); |
||||
} else if (baseResp.errCode == -1) {//错误可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
|
||||
weChatManager.mWXPayResultData.postValue(Status.error(new WeChatPayException(baseResp.errStr))); |
||||
} else if (baseResp.errCode == -2) {//用户取消无需处理。发生场景:用户不支付了,点击取消,返回APP。
|
||||
weChatManager.mWXPayResultData.postValue(Status.cancel()); |
||||
} |
||||
} |
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 分享
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public boolean share(WeChatShareInfo.ShareContent content) { |
||||
try { |
||||
SendMessageToWX.Req baseReq = WeChatShareInfo.buildReq(content); |
||||
mWxApi.sendReq(baseReq); |
||||
return true; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static void handleSendMessageResp(BaseResp baseResp) { |
||||
switch (baseResp.errCode) { |
||||
case BaseResp.ErrCode.ERR_OK: |
||||
//todo success
|
||||
break; |
||||
case BaseResp.ErrCode.ERR_USER_CANCEL: |
||||
//todo canceled
|
||||
break; |
||||
case BaseResp.ErrCode.ERR_AUTH_DENIED: |
||||
case BaseResp.ErrCode.ERR_SENT_FAILED: |
||||
case BaseResp.ErrCode.ERR_UNSUPPORT: |
||||
case BaseResp.ErrCode.ERR_COMM: |
||||
case BaseResp.ErrCode.ERR_BAN: |
||||
//todo error
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,14 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2019-05-10 16:53 |
||||
*/ |
||||
public class WeChatPayException extends Exception { |
||||
|
||||
public WeChatPayException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
} |
@ -1,115 +0,0 @@ |
||||
package com.android.sdk.social.wechat; |
||||
|
||||
import android.support.annotation.Nullable; |
||||
|
||||
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX; |
||||
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage; |
||||
import com.tencent.mm.opensdk.modelmsg.WXWebpageObject; |
||||
|
||||
/** |
||||
* @author Ztiany |
||||
* Email: ztiany3@gmail.com |
||||
* Date : 2019-08-27 17:04 |
||||
*/ |
||||
public class WeChatShareInfo { |
||||
|
||||
public static final int SCENE_FRIEND = 1; |
||||
public static final int SCENE_MOMENT = 2; |
||||
public static final int SCENE_FAVORITE = 3; |
||||
|
||||
abstract static class ShareContent { |
||||
} |
||||
|
||||
public static class Url extends ShareContent { |
||||
|
||||
private int scene; |
||||
private String webpageUrl; |
||||
private String title; |
||||
private String description; |
||||
@Nullable |
||||
private byte[] thumbBmp; |
||||
|
||||
public void setScene(int scene) { |
||||
this.scene = scene; |
||||
} |
||||
|
||||
String getWebpageUrl() { |
||||
return webpageUrl; |
||||
} |
||||
|
||||
public void setWebpageUrl(String webpageUrl) { |
||||
this.webpageUrl = webpageUrl; |
||||
} |
||||
|
||||
String getTitle() { |
||||
return title; |
||||
} |
||||
|
||||
public void setTitle(String title) { |
||||
this.title = title; |
||||
} |
||||
|
||||
String getDescription() { |
||||
return description; |
||||
} |
||||
|
||||
public void setDescription(String description) { |
||||
this.description = description; |
||||
} |
||||
|
||||
@Nullable |
||||
byte[] getThumbBmp() { |
||||
return thumbBmp; |
||||
} |
||||
|
||||
public void setThumbBmp(@Nullable byte[] thumbBmp) { |
||||
this.thumbBmp = thumbBmp; |
||||
} |
||||
|
||||
private int getScene() { |
||||
return scene; |
||||
} |
||||
} |
||||
|
||||
static SendMessageToWX.Req buildReq(ShareContent shareContent) { |
||||
if (shareContent instanceof Url) { |
||||
return buildUrlReq((Url) shareContent); |
||||
} |
||||
throw new UnsupportedOperationException("不支持的分享内容"); |
||||
} |
||||
|
||||
private static SendMessageToWX.Req buildUrlReq(Url shareContent) { |
||||
//初始化一个WXWebpageObject,填写url
|
||||
WXWebpageObject webpage = new WXWebpageObject(); |
||||
webpage.webpageUrl = shareContent.getWebpageUrl(); |
||||
|
||||
//用 WXWebpageObject 对象初始化一个 WXMediaMessage 对象
|
||||
WXMediaMessage msg = new WXMediaMessage(webpage); |
||||
msg.title = shareContent.getTitle(); |
||||
msg.description = shareContent.getDescription(); |
||||
if (shareContent.getThumbBmp() != null) { |
||||
msg.thumbData = shareContent.getThumbBmp(); |
||||
} |
||||
|
||||
//构造一个Req
|
||||
SendMessageToWX.Req req = new SendMessageToWX.Req(); |
||||
req.message = msg; |
||||
req.scene = mapScene(shareContent.getScene()); |
||||
req.userOpenId = WeChatManager.getAppId(); |
||||
return req; |
||||
} |
||||
|
||||
private static int mapScene(int scene) { |
||||
if (scene == SCENE_FAVORITE) { |
||||
return SendMessageToWX.Req.WXSceneFavorite; |
||||
} |
||||
if (scene == SCENE_FRIEND) { |
||||
return SendMessageToWX.Req.WXSceneSession; |
||||
} |
||||
if (scene == SCENE_MOMENT) { |
||||
return SendMessageToWX.Req.WXSceneTimeline; |
||||
} |
||||
throw new UnsupportedOperationException("不支持的场景"); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue