package com.mango.moshen.application; import static com.mango.xchat_android_constants.XChatConstants.HW_APP_ID; import static com.mango.xchat_android_constants.XChatConstants.HW_CERTIFICATE_NAME; import static com.mango.xchat_android_constants.XChatConstants.OPPO_APP_ID; import static com.mango.xchat_android_constants.XChatConstants.OPPO_APP_KEY; import static com.mango.xchat_android_constants.XChatConstants.OPPO_CERTIFICATE_NAME; import static com.mango.xchat_android_constants.XChatConstants.OPPO_SECRET; import static com.mango.xchat_android_constants.XChatConstants.VIVO_CERTIFICATE_NAME; import static com.mango.xchat_android_constants.XChatConstants.XM_APP_ID; import static com.mango.xchat_android_constants.XChatConstants.XM_APP_KEY; import static com.mango.xchat_android_constants.XChatConstants.XM_CERTIFICATE_NAME; import static com.mango.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_HEADER_TYPE_OPEN_ROOM_NOTI; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Application; import android.content.Context; import android.graphics.Color; import android.net.http.HttpResponseCache; import android.os.Build; import android.os.Environment; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import androidx.multidex.MultiDex; import com.bumptech.glide.request.target.ViewTarget; import com.bytedance.hume.readapk.HumeSDK; import com.coorchice.library.utils.LogUtils; import com.heytap.msp.push.HeytapPushManager; import com.hjq.toast.ToastUtils; import com.huawei.hms.support.common.ActivityMgr; import com.llew.huawei.verifier.LoadedApkHuaWei; import com.microquation.linkedme.android.LinkedME; import com.mob.MobSDK; import com.netease.nim.uikit.api.NimUIKit; import com.netease.nim.uikit.common.util.log.LogUtil; import com.netease.nimlib.sdk.NIMClient; import com.netease.nimlib.sdk.NotificationFoldStyle; import com.netease.nimlib.sdk.SDKOptions; import com.netease.nimlib.sdk.StatusBarNotificationConfig; import com.netease.nimlib.sdk.mixpush.MixPushConfig; import com.netease.nimlib.sdk.mixpush.NIMPushClient; import com.netease.nimlib.sdk.msg.MessageNotifierCustomization; import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; import com.netease.nimlib.sdk.msg.model.IMMessage; import com.netease.nimlib.sdk.util.NIMUtil; import com.opensource.svgaplayer.SVGAParser; import com.orhanobut.logger.AndroidLogAdapter; import com.orhanobut.logger.Logger; import com.scwang.smartrefresh.header.MaterialHeader; import com.scwang.smartrefresh.layout.SmartRefreshLayout; import com.scwang.smartrefresh.layout.footer.ClassicsFooter; import com.tencent.bugly.Bugly; import com.tencent.bugly.beta.Beta; import com.tencent.bugly.crashreport.CrashReport; import com.tencent.vasdolly.helper.ChannelReaderUtil; import com.umeng.analytics.MobclickAgent; import com.umeng.commonsdk.UMConfigure; import com.mango.moshen.BuildConfig; import com.mango.moshen.MainActivity; import com.mango.moshen.MiddleActivity; import com.mango.moshen.NimMiddleActivity; import com.mango.moshen.R; import com.mango.moshen.module_hall.HallDataManager; import com.mango.moshen.other.activity.SplashActivity; import com.mango.moshen.quick_pass.QuickPassLoginAct; import com.mango.moshen.radish.wallet.RadishWalletManager; import com.mango.moshen.utils.PushMessageHandler; import com.mango.xchat_android_constants.XChatConstants; import com.mango.core.Constants; import com.mango.core.DemoCache; import com.mango.core.Env; import com.mango.core.UriProvider; import com.mango.core.auth.AuthModel; import com.mango.core.bean.response.ServiceResult; import com.mango.core.channel.ChannelModel; import com.mango.core.family.model.FamilyModel; import com.mango.core.gift.GiftModel; import com.mango.core.im.custom.bean.CustomAttachment; import com.mango.core.im.custom.bean.OpenSignInAttachment; import com.mango.core.initial.InitialModel; import com.mango.core.interceptor.NoParamsInterceptor; import com.mango.core.interceptor.ParamsInterceptor; import com.mango.core.manager.IMMessageManager; import com.mango.core.manager.IMSystemMsgManager; import com.mango.core.market_verify.MarketVerifyModel; import com.mango.core.mentoring_relationship.model.MentoringRelationshipModel; import com.mango.core.pay.PayModel; import com.mango.core.public_chat_hall.model.PublicChatHallModel; import com.mango.core.radish.RadishModel; import com.mango.core.radish.signin.bean.ImNotice; import com.mango.core.room.face.DynamicFaceModel; import com.mango.core.statistic.StatisticManager; import com.mango.core.statistic.protocol.StatisticsProtocol; import com.mango.core.user.UserModel; import com.mango.core.user.event.NeedCompleteInfoEvent; import com.mango.core.utils.SharedPreferenceUtils; import com.mango.core.utils.net.ServerException; import com.mango.xchat_android_library.net.rxnet.RxNet; import com.mango.xchat_android_library.net.rxnet.converter.GsonConverterPlugins; import com.mango.xchat_android_library.utils.AppMetaDataUtil; import com.mango.xchat_android_library.utils.AppUtils; import com.mango.xchat_android_library.utils.DeviceUuidFactory; import com.mango.xchat_android_library.utils.SingleToastUtil; import com.mango.xchat_android_library.utils.SystemUtils; import com.mango.xchat_android_library.utils.VersionUtil; import com.mango.xchat_android_library.utils.codec.MD5Utils; import com.mango.xchat_android_library.utils.config.BasicConfig; import org.greenrobot.eventbus.EventBus; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import io.reactivex.plugins.RxJavaPlugins; import io.realm.Realm; import io.realm.RealmConfiguration; /** * @author chenran * @date 2017/2/11 */ public class XChatApplication extends Application { public static final String TAG = "XChatApplication"; private static final MessageNotifierCustomization messageNotifierCustomization = new MessageNotifierCustomization() { @Override public String makeNotifyContent(String nick, IMMessage message) { if (message.getMsgType() == MsgTypeEnum.custom) { CustomAttachment customAttachment = (CustomAttachment) message.getAttachment(); if (customAttachment.getFirst() == CUSTOM_MSG_HEADER_TYPE_OPEN_ROOM_NOTI) { return message.getFromNick(); } else if (customAttachment instanceof OpenSignInAttachment) { return getContentFromOpenSignIn(customAttachment); } } // 采用SDK默认文案 return "收到一条消息"; } @Override public String makeTicker(String nick, IMMessage message) { if (message.getMsgType() == MsgTypeEnum.custom) { CustomAttachment customAttachment = (CustomAttachment) message.getAttachment(); if (customAttachment != null) { if (customAttachment.getFirst() == CUSTOM_MSG_HEADER_TYPE_OPEN_ROOM_NOTI) { return message.getFromNick(); } else if (customAttachment instanceof OpenSignInAttachment) { return getContentFromOpenSignIn(customAttachment); } } } // 采用SDK默认文案 return "收到一条消息"; } private String getContentFromOpenSignIn(CustomAttachment attachment) { String result = null; if (attachment instanceof OpenSignInAttachment) { ImNotice notice = ((OpenSignInAttachment) attachment).getImNotice(); if (notice != null) { result = notice.getContent(); } } if (TextUtils.isEmpty(result)) { result = "收到一条消息"; } return result; } @Override public String makeRevokeMsgTip(String s, IMMessage imMessage) { return null; } }; private static XChatApplication instance; //生命周期监听 private static ActivityLifeManager lifeManager; private static boolean isInitOtherSDK = false; //static 代码段可以防止内存泄露 static { SmartRefreshLayout.setDefaultRefreshHeaderCreater( (context, layout) -> { layout.setEnableHeaderTranslationContent(false); MaterialHeader materialHeader = new MaterialHeader(context); materialHeader.setShowBezierWave(false); return materialHeader; }); SmartRefreshLayout.setDefaultRefreshFooterCreater( (context, layout) -> new ClassicsFooter(context).setDrawableSize(20)); } public static XChatApplication instance() { return instance; } public static void initOtherSDK() { if (isInitOtherSDK) return; isInitOtherSDK = true; Context context = BasicConfig.INSTANCE.getAppContext(); Application application = (Application) context.getApplicationContext(); // 初始化 sp long startTime = System.currentTimeMillis(); String channel = ""; channel = ChannelReaderUtil.getChannel(instance); if (TextUtils.isEmpty(channel)) { channel = "official"; } BasicConfig.INSTANCE.setOriginalChannel(channel); //头条分包渠道 if (BasicConfig.INSTANCE.isByteDanceChannel()) { String byteDanceChannel = HumeSDK.getChannel(context); if (!TextUtils.isEmpty(byteDanceChannel)) { channel = byteDanceChannel; } } BasicConfig.INSTANCE.setChannel(channel); initEnv(); ActivityMgr.INST.init((Application) context); //延迟初始化云信 NIMClient.init(context, null, options()); //logger 配置 Logger.addLogAdapter(new AndroidLogAdapter() { @Override public boolean isLoggable(int priority, String tag) { return BuildConfig.DEBUG; } }); ToastUtils.init(application); if (inMainProcess(context)) { HeytapPushManager.init(context, true); DemoCache.saveLaunchCount(); // 注册自定义推送消息处理,这个是可选项 NIMPushClient.registerMixPushMessageHandler(new PushMessageHandler()); RxJavaPlugins.setErrorHandler(throwable -> { if (BuildConfig.DEBUG) { Log.e(TAG, "the subscribe() method default error handler", throwable); } }); //需要完善资料错误码全局处理 GsonConverterPlugins.setResultHandler(result -> { if (result instanceof ServiceResult) { ServiceResult serviceResult = (ServiceResult) result; if (serviceResult.getCode() == ServiceResult.CODE_NEED_COMPLETE_USER_INFO) { SingleToastUtil.showToast(serviceResult.getMessage()); EventBus.getDefault().post(new NeedCompleteInfoEvent()); throw new ServerException(serviceResult.getMessage(), serviceResult.getCode()); } } return null; }); GsonConverterPlugins.lockdown(); //fixed: Glide Exception:"You must not call setTag() on a view Glide is targeting" ViewTarget.setTagId(R.id.tag_glide); init(channel); if (!TextUtils.isEmpty(channel)) { CrashReport.setAppChannel(context, channel); } initBuglyUpdate(); Bugly.init(context, BuildConfig.DEBUG ? XChatConstants.BUGLY_KEY_DEBUG : XChatConstants.BUGLY_KEY_RELEASE, BuildConfig.DEBUG); //生命周期监听 if (lifeManager == null) { lifeManager = new ActivityLifeManager(); } registerActivityLifecycleCallback(lifeManager); dealHuaWeiCrash(); initLinkedMe(); LinkedME.getInstance().setImmediate(true); MobSDK.init(context); MobSDK.submitPolicyGrantResult(true); // 友盟统计初始化 UMConfigure.init(context, XChatConstants.UMENG_APP_KEY, BasicConfig.INSTANCE.getChannel(), UMConfigure.DEVICE_TYPE_PHONE, null); // 选用MANUAL页面采集模式 MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.MANUAL); // 支持在子进程中统计自定义事件 UMConfigure.setProcessEvent(true); // 日志加密 UMConfigure.setEncryptEnabled(true); // 集成测试 UMConfigure.setLogEnabled(BuildConfig.DEBUG); } LogUtils.d("init time = " + (System.currentTimeMillis() - startTime) + "ms"); } /** * 初始化linkedMe */ private static void initLinkedMe() { LinkedME.getInstance(BasicConfig.INSTANCE.getAppContext(), XChatConstants.LINKED_ME_KEY); if (isDebug()) { //设置debug模式下打印LinkedME日志 LinkedME.getInstance().setDebug(); } //初始时请设置为false LinkedME.getInstance().setImmediate(false); //设置处理跳转逻辑的中转页,MiddleActivity详见后续配置 LinkedME.getInstance().setHandleActivity(MiddleActivity.class.getName()); } private static void initEnv() { //首先初始化环境 Env.initEnv(BuildConfig.BUILD_TYPE, BuildConfig.DEBUG); //切换生产坏境和测试环境 true/测试环境 false/生产环境 BasicConfig.INSTANCE.setDebuggable(Env.isDebug()); BasicConfig.INSTANCE.setRootDir(Constants.ERBAN_DIR_NAME); BasicConfig.INSTANCE.setLogDir(Constants.LOG_DIR); BasicConfig.INSTANCE.setConfigDir(Constants.CONFIG_DIR); BasicConfig.INSTANCE.setVoiceDir(Constants.VOICE_DIR); BasicConfig.INSTANCE.setCacheDir(Constants.CACHE_DIR); BasicConfig.INSTANCE.setImageDir(Constants.IMAGE_CACHE_DIR); } private static void dealHuaWeiCrash() { String brand = Build.BRAND; String manufacturer = Build.MANUFACTURER; if (!TextUtils.isEmpty(brand) && ( "HUAWEI".toLowerCase().equals(brand.toLowerCase()) || "HONOR".toLowerCase().equals(brand.toLowerCase()) || "HUAWEI".equals(manufacturer))) { LoadedApkHuaWei.hookHuaWeiVerifier((Application) BasicConfig.INSTANCE.getAppContext().getApplicationContext()); } } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public static void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) { ((Application) BasicConfig.INSTANCE.getAppContext().getApplicationContext()).registerActivityLifecycleCallbacks(callbacks); } /** * 云信配置 * * @return */ public static SDKOptions options() { SDKOptions options = new SDKOptions(); options.disableAwake = true; options.asyncInitSDK = true; // options.customPushContentType = ""; if (isDebug()) { options.checkManifestConfig = true; } // 如果将新消息通知提醒托管给 SDK 完成,需要添加以下配置。否则无需设置。 StatusBarNotificationConfig config = new StatusBarNotificationConfig(); // 点击通知栏跳转到该Activity config.notificationEntrance = NimMiddleActivity.class; // config.notificationSmallIconId = R.drawable.icon_msg_normal; // 呼吸灯配置 config.ledARGB = Color.GREEN; config.ledOnMs = 1000; config.ledOffMs = 1500; config.notificationFoldStyle = NotificationFoldStyle.CONTACT; // 通知铃声的uri字符串 config.notificationSound = "android.resource://com.netease.nim.demo/raw/msg"; options.statusBarNotificationConfig = config; // 定制通知栏提醒文案(可选,如果不定制将采用SDK默认文案) options.messageNotifierCustomization = messageNotifierCustomization; options.appKey = Constants.nimAppKey; // 配置保存图片,文件,log 等数据的目录 // 如果 options 中没有设置这个值,SDK 会使用下面代码示例中的位置作为 SDK 的数据目录。 // 该目录目前包含 log, file, image, audio, video, thumb 这6个目录。 // 如果第三方 APP 需要缓存清理功能, 清理这个目录下面个子目录的内容即可。 String sdkPath = null; try { sdkPath = Environment.getExternalStorageDirectory() + "/" + BasicConfig.INSTANCE.getAppContext().getPackageName() + "/nim"; } catch (ArrayIndexOutOfBoundsException e) { } options.sdkStorageRootPath = sdkPath; // 配置是否需要预下载附件缩略图,默认为 true options.preloadAttach = true; // 配置附件缩略图的尺寸大小。表示向服务器请求缩略图文件的大小 // 该值一般应根据屏幕尺寸来确定, 默认值为 Screen.width / 2 int widthPixels = BasicConfig.INSTANCE.getAppContext().getResources().getDisplayMetrics().widthPixels; options.thumbnailSize = widthPixels / 2; // // save cache,留做切换账号备用 DemoCache.setNotificationConfig(config); MixPushConfig mixPushConfig = new MixPushConfig(); //华为推送 mixPushConfig.hwAppId = HW_APP_ID; mixPushConfig.hwCertificateName = HW_CERTIFICATE_NAME; //小米推送 mixPushConfig.xmAppId = XM_APP_ID; mixPushConfig.xmAppKey = XM_APP_KEY; mixPushConfig.xmCertificateName = XM_CERTIFICATE_NAME; //vivo推送 mixPushConfig.vivoCertificateName = VIVO_CERTIFICATE_NAME; //oppo推送 mixPushConfig.oppoAppId = OPPO_APP_ID; mixPushConfig.oppoAppKey = OPPO_APP_KEY; mixPushConfig.oppoAppSercet = OPPO_SECRET; mixPushConfig.oppoCertificateName = OPPO_CERTIFICATE_NAME; options.mixPushConfig = mixPushConfig; return options; } /** * 判断当前进程是否主进程 * * @param context * @return */ private static boolean inMainProcess(Context context) { String packageName = context.getPackageName(); String processName = NIMUtil.getProcessName(context); return packageName.equals(processName); } /** * 初始化bugly版本升级 */ private static void initBuglyUpdate() { /***** Beta高级设置 *****/ /** * true表示app启动自动初始化升级模块; * false不会自动初始化; * 开发者如果担心sdk初始化影响app启动速度,可以设置为false, * 在后面某个时刻手动调用Beta.init(getApplicationContext(),false); */ // Beta.autoInit = true; /** * true表示初始化时自动检查升级; * false表示不会自动检查升级,需要手动调用Beta.checkUpgrade()方法; */ // Beta.autoCheckUpgrade = true; /** * 设置升级检查周期为60s(默认检查周期为0s),60s内SDK不重复向后台请求策略); */ // Beta.upgradeCheckPeriod = 60 * 1000; /** * 设置启动延时为1s(默认延时3s),APP启动1s后初始化SDK,避免影响APP启动速度; */ Beta.initDelay = 6 * 1000; /** * 设置sd卡的Download为更新资源保存目录; * 后续更新资源会保存在此目录,需要在manifest中添加WRITE_EXTERNAL_STORAGE权限; */ // Beta.storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); /** * 点击过确认的弹窗在APP下次启动自动检查更新时会再次显示; */ Beta.showInterruptedStrategy = true; /** * 只允许在MainActivity上显示更新弹窗,其他activity上不显示弹窗; * 不设置会默认所有activity都可以显示弹窗; * 2021/6/22 增加登录页面也可以弹出,万一域名挂了还可以用bugly更新!! */ Beta.canShowUpgradeActs.add(MainActivity.class); Beta.canShowUpgradeActs.add(QuickPassLoginAct.class); /** * 自定义布局 */ Beta.upgradeDialogLayoutId = R.layout.upgrade_dialog;//关键代码写这个布局添加自己想要的 } /** * 初始化RxNet * * @param context * @param url */ @SuppressLint("CheckResult") public static void initRxNet(Context context, String url) { Map httpParams = new ConcurrentHashMap<>(); httpParams.put("os", "android"); httpParams.put("osVersion", Build.VERSION.RELEASE); httpParams.put("app", XChatConstants.APP_MARK); httpParams.put("ispType", String.valueOf(SystemUtils.getIspType(context))); httpParams.put("netType", String.valueOf(SystemUtils.getNetworkType(context))); httpParams.put("model", SystemUtils.getPhoneModel()); httpParams.put("appVersion", VersionUtil.getLocalName(context)); httpParams.put("appVersionCode", String.valueOf(AppUtils.getVersionCode(context))); httpParams.put("deviceId", DeviceUuidFactory.getDeviceId(context)); httpParams.put("androidId", MD5Utils.getMD5String(Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID))); httpParams.put("channel", AppMetaDataUtil.getChannelID()); RxNet.init(context) .debug(BuildConfig.DEBUG) .setBaseUrl(url) .addInterceptors(new ParamsInterceptor(httpParams)) .addInterceptors(new NoParamsInterceptor())//注意:拦截器的添加顺序,请求的拦截顺序 .build(); //单例的model 初始化 initModel(); } private static void init(String channel) { initNimUIKit(); UriProvider.initUri(BuildConfig.BASE_URL_DEBUG, BuildConfig.BASE_URL_STAGING, BuildConfig.BASE_URL_RELEASE); SVGAParser.Companion.shareParser().init(BasicConfig.INSTANCE.getAppContext()); try { /** svga动画缓存路径 */ File cacheDir = new File(BasicConfig.INSTANCE.getAppContext().getApplicationContext().getExternalCacheDir(), "http"); if (!cacheDir.exists()) cacheDir.mkdirs(); HttpResponseCache.install(cacheDir, 1024 * 1024 * 128); } catch (IOException e) { Log.e(TAG, "testtest", e); } initRxNet(BasicConfig.INSTANCE.getAppContext(), UriProvider.JAVA_WEB_URL); /** * 使用到realm 数据库,这里配置数据库 这里必须先于模块初始化前进行初始化配置 */ Realm.init(BasicConfig.INSTANCE.getAppContext()); RealmConfiguration config = new RealmConfiguration.Builder() .name("accompany.realm") .deleteRealmIfMigrationNeeded() .build(); Realm.setDefaultConfiguration(config); LogUtil.i(TAG, channel); //APP启动埋点 StatisticManager.Instance().onEvent(StatisticsProtocol.EVENT_APP_LAUNCH, "应用启动"); } /** * 一些单例的 model */ private static void initModel() { DynamicFaceModel.get().init(); PayModel.get(); UserModel.get(); //ui层的萝卜钱包 RadishWalletManager.get(); //model层的 RadishModel.get(); IMMessageManager.get().init(); IMSystemMsgManager.get().init(); FamilyModel.Instance(); AuthModel.get(); ChannelModel.get(); MarketVerifyModel.get(); GiftModel.get(); PublicChatHallModel.get(); // 模厅 HallDataManager.get().application(); // 师徒 MentoringRelationshipModel.get(); //全局处理 GlobalHandleManager.get().init(); InitialModel.get().init(true).subscribe(); } private static void initNimUIKit() { // 初始化 NimUIKit.init(BasicConfig.INSTANCE.getAppContext()); } /** * debug 环境 受到实验室模式影响 */ public static boolean isDebug() { return Env.isDebug(); } /** * 是否是真实的debug的环境 不受实验室模式影响 * * @return */ public static boolean isRealDebug() { return Env.isRealDebug(); } /** * 用户没同意隐私协议之前,啥也不干!! */ @Override public void onCreate() { super.onCreate(); instance = this; BasicConfig.INSTANCE.setAppContext(this.getApplicationContext()); SharedPreferenceUtils.init(this); boolean isShowPrivacyAgreement = (boolean) SharedPreferenceUtils.get(SplashActivity.SHOW_PRIVACY_AGREEMENT, true); if (!isShowPrivacyAgreement) { initOtherSDK(); } } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(base); } @Override public void onTerminate() { super.onTerminate(); CrashReport.closeBugly(); if (lifeManager != null) { unregisterActivityLifecycleCallbacks(lifeManager); } GlobalHandleManager.get().unInit(); } }