9 Commits

44 changed files with 666 additions and 117 deletions

View File

@@ -3,12 +3,9 @@ apply plugin: 'com.android.application'
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'com.huawei.agconnect'
apply plugin: 'com.tencent.vasdolly'
apply from: '../mob.gradle'
apply plugin: 'android-junk-code'
def onlyArm64 = Boolean.parseBoolean(only_arm64)
android {
compileSdkVersion COMPILE_SDK_VERSION.toInteger()
@@ -21,20 +18,20 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
}
// ndk {
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
// }
flavorDimensions 'default'
}
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86'
universalApk true
}
}
// splits {
// abi {
// enable true
// reset()
// include 'armeabi-v7a', 'arm64-v8a', 'x86'
// universalApk true
// }
// }
//在apk文件后边生成版本号信息
android.applicationVariants.configureEach { variant ->
@@ -50,7 +47,7 @@ android {
if (abi == null) {
abi = "universal"
}
outputFileName = "yinmeng_${buildType.name}_v${defaultConfig.versionName}_${abi}_${date}.apk"
outputFileName = "yinmeng_${variant.flavorName}_${buildType.name}_v${defaultConfig.versionName}_${defaultConfig.versionCode}_${abi}_${date}.apk"
}
}
@@ -182,6 +179,54 @@ android {
buildToolsVersion = '30.0.3'
productFlavors {
official {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
mlq {
ndk {
abiFilters 'x86'
}
}
yingyongbao {
ndk {
abiFilters 'armeabi-v7a'
}
}
vivo {
ndk {
abiFilters 'arm64-v8a'
}
}
oppo {
ndk {
abiFilters 'arm64-v8a'
}
}
xiaomi {
ndk {
abiFilters 'arm64-v8a'
}
}
huawei {
ndk {
abiFilters 'arm64-v8a'
}
}
kuaishou_01 {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [
// 渠道
CHANNEL_VALUE : name,
]
}
}
@@ -258,7 +303,7 @@ dependencies {
//oppo推送需要
implementation 'commons-codec:commons-codec:1.6'
api 'com.tencent.vasdolly:helper:3.0.3'
// api 'com.tencent.vasdolly:helper:3.0.3'
implementation "io.github.tencent:vap:2.0.24"
implementation 'com.github.mmin18:realtimeblurview:1.2.1'
@@ -276,36 +321,20 @@ repositories {
}
channel {
//多渠道包的输出目录默认为new File(project.buildDir,"channel")
outputDir = new File(project.buildDir, "channelapk")
//多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}-${buildTime}
def only64 = onlyArm64 ? "-only64" : ""
apkNameFormat = 'yinmeng-${buildType}only64-${flavorName}-v${versionName}-${buildTime}'.replace("only64", only64)
//快速模式生成渠道包时不进行校验速度可以提升10倍以上默认为false
fastMode = false
//buildTime的时间格式默认格式yyyyMMdd-HHmmss
buildTimeDateFormat = 'MMddHHmm'
//低内存模式仅针对V2签名默认为false只把签名块、中央目录和EOCD读取到内存不把最大头的内容块读取到内存在手机上合成APK时可以使用该模式
lowMemory = false
}
android.applicationVariants.all { variant ->
print("variant.name=" + variant.name)
switch (variant.name) {//变体名称如果没有设置productFlavors就是buildType名称如果有设置productFlavors就是flavor+buildType例如freeRelease、proRelease
case "release":
androidJunkCode.configMap.put(variant.name, {
packageBase = "com.nnbc123.plugin.ui" //生成java类根包名
packageCount = 30 //生成包数量
activityCountPerPackage = 30 //每个包下生成Activity类数量
excludeActivityJavaFile = false
//是否排除生成Activity的Java文件,默认false(layout和写入AndroidManifest.xml还会执行),主要用于处理类似神策全埋点编译过慢问题
otherCountPerPackage = 50 //每个下生成其它类的数量
methodCountPerClass = 20 //每个类下生成方法数量
resPrefix = "mango_" //生成的layout、drawable、string等资源名前缀
drawableCount = 300 //生成drawable资源数量
stringCount = 300 //生成string数量
})
break
if (variant.name.contains("release") || variant.name.contains("Release")) {
androidJunkCode.configMap.put(variant.name, {
packageBase = "com.nnbc123.plugin.ui" //生成java类根包名
packageCount = 30 //生成包数量
activityCountPerPackage = 30 //每个包下生成Activity类数量
excludeActivityJavaFile = false
//是否排除生成ActivityJava文件,默认false(layout和写入AndroidManifest.xml还会执行),主要用于处理类似神策全埋点编译过慢问题
otherCountPerPackage = 50 //每个包下生成其它类的数量
methodCountPerClass = 20 //每个下生成方法数量
resPrefix = "mango_" //生成的layout、drawable、string等资源名前缀
drawableCount = 300 //生成drawable资源数量
stringCount = 300 //生成string数量
})
}
}

View File

@@ -86,6 +86,10 @@
android:theme="@style/MyMaterialTheme"
android:usesCleartextTraffic="true"
tools:replace="android:name,android:allowBackup">
<!-- 多渠道 -->
<meta-data
android:name="CHANNEL"
android:value="${CHANNEL_VALUE}" />
<!-- 刘海屏适配 begin -->
<!-- 小米 -->
<meta-data

View File

@@ -28,6 +28,7 @@ import androidx.multidex.MultiDex;
import com.bumptech.glide.request.target.ViewTarget;
import com.bytedance.hume.readapk.HumeSDK;
import com.chuhai.utils.MetaDataUtils;
import com.coorchice.library.utils.LogUtils;
import com.facebook.stetho.Stetho;
import com.heytap.msp.push.HeytapPushManager;
@@ -61,7 +62,6 @@ 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.nnbc123.app.BuildConfig;
@@ -213,12 +213,12 @@ public class XChatApplication extends BaseApp {
// 初始化 sp
long startTime = System.currentTimeMillis();
String channel = "";
channel = ChannelReaderUtil.getChannel(instance);
String channel;
channel = MetaDataUtils.INSTANCE.getStringData(Constants.CHANNEL_KEY, application);
if (TextUtils.isEmpty(channel)) {
channel = "official";
}
Log.d("XChatApplication", "channel:" + channel);
BasicConfig.INSTANCE.setOriginalChannel(channel);
//头条分包渠道
@@ -228,6 +228,7 @@ public class XChatApplication extends BaseApp {
channel = byteDanceChannel;
}
}
Log.d("XChatApplication", "channel2:" + channel);
BasicConfig.INSTANCE.setChannel(channel);
initEnv();

View File

@@ -3,13 +3,16 @@ package com.nnbc123.app.avroom.fragment
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.text.TextUtils
import android.text.style.ForegroundColorSpan
import android.view.*
@@ -115,6 +118,7 @@ import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder
import com.netease.nimlib.sdk.chatroom.model.ChatRoomKickOutEvent
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import com.nnbc123.app.avroom.hour_rank.RoomHourRankWidget
import com.nnbc123.app.ui.widget.dialog.CommonTipDialog
import com.orhanobut.logger.Logger
import com.tbruyelle.rxpermissions2.RxPermissions
import com.trello.rxlifecycle3.android.FragmentEvent
@@ -1146,11 +1150,37 @@ open class BaseRoomFragment<V : IBaseRoomView?, P : BaseRoomPresenter<V>?> :
if (result) {
mvpPresenter?.upMicroPhone(micPosition, currentUid, b)
} else {
toast("请给予麦克风权限后再试!")
showDeniedTips(
requireContext(),
ResUtil.getString(R.string.permission_denied_tips_mic)
)
}
}, { throwable: Throwable? -> toast("发生一些异常,请稍后重试!") })
}
private fun showDeniedTips(context: Context, message: String) {
CommonTipDialog(context).apply {
setTipMsg(message)
setOkText("去设置")
setOnActionListener(
object : CommonTipDialog.OnActionListener {
override fun onOk() {
//同意跳到应用详情页面
val packageUri =
Uri.parse("package:${context.packageName}")
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
packageUri
)
(context as? Activity)?.startActivityForResult(
intent, 0
)
}
}
)
}.show()
}
/**
* 是否有麦克风权限
*

View File

@@ -554,36 +554,20 @@ class HomePartyFragment : BaseFragment(), View.OnClickListener, OnShareDialogIte
.compose(bindToLifecycle())
.compose(RxHelper.handleBeanData())
.subscribe { roomContributeDataInfo: RoomContributeDataInfo ->
val rankings = roomContributeDataInfo.rankings
updateRoomRanks(roomContributeDataInfo.rankings)
var imageView: ImageView
val avatarList = listOf(
binding.ivRank0,
binding.ivRank1,
binding.ivRank2
)
for (i in avatarList.indices) {
imageView = avatarList[i]
if (rankings.size > i) {
val info = rankings[i]
imageView.loadAvatar(info.avatar)
} else {
imageView.setImageResource(R.drawable.default_avatar)
}
}
}
}
private fun updateRoomRanks(data: List<RoomContributeUserInfo>) {
val avatarList = arrayListOf(
binding.ivRank0,
// binding.ivRank1,
// binding.ivRank2
binding.ivRank1,
binding.ivRank2
)
val stvList = arrayListOf(
binding.stvRank0,
// binding.stvRank1,
// binding.stvRank2
binding.stvRank1,
binding.stvRank2
)
for (i in 0 until avatarList.size) {
avatarList[i].loadAvatar(data.getOrNull(i)?.avatar)

View File

@@ -34,6 +34,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.annotation.ColorInt;
import androidx.core.util.Consumer;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@@ -133,7 +134,7 @@ public abstract class BaseActivity extends RxAppCompatActivity
*/
protected static final String STATUS_TAG = "STATUS_TAG";
private final RxPermissions rxPermissions = new RxPermissions(this);
protected final RxPermissions rxPermissions = new RxPermissions(this);
protected TitleBar mTitleBar;
protected DefaultToolBar mToolBar;
protected CompositeDisposable mCompositeDisposable;
@@ -821,6 +822,17 @@ public abstract class BaseActivity extends RxAppCompatActivity
}, Throwable::printStackTrace);
}
@SuppressLint("CheckResult")
public void checkPermission(Consumer<Boolean> consumer, String... mPerms) {
rxPermissions.request(mPerms)
.subscribe(aBoolean -> {
if (consumer != null) {
consumer.accept(aBoolean);
}
}, Throwable::printStackTrace);
}
@SuppressLint("CheckResult")
public Observable<Boolean> checkPermission(String... mPerms) {
return rxPermissions.request(mPerms);

View File

@@ -0,0 +1,26 @@
package com.nnbc123.app.common.permission
import com.tbruyelle.rxpermissions2.RxPermissions
/**
* Created by Max on 2024/1/8 10:25
* Desc:
**/
object PermissionHelper {
/**
* 检查权限是否都授权
*/
fun isAllGender(rxPermissions: RxPermissions, vararg perms: String?): Boolean {
if (perms.firstOrNull {
if (it == null) {
false
} else {
!rxPermissions.isGranted(it)
}
} != null) {
return false
}
return true
}
}

View File

@@ -21,6 +21,11 @@ import com.qiyukf.unicorn.api.YSFOptions;
import com.qiyukf.unicorn.api.YSFUserInfo;
import com.qiyukf.unicorn.api.customization.input.ActionPanelOptions;
import com.qiyukf.unicorn.api.customization.input.InputPanelOptions;
import com.qiyukf.unicorn.api.event.EventCallback;
import com.qiyukf.unicorn.api.event.EventProcessFactory;
import com.qiyukf.unicorn.api.event.SDKEvents;
import com.qiyukf.unicorn.api.event.UnicornEventBase;
import com.qiyukf.unicorn.api.event.entry.RequestPermissionEventEntry;
import com.soundcloud.android.crop.UriUtil;
import java.util.ArrayList;
@@ -109,7 +114,17 @@ public class CustomerServerHelper {
options.uiCustomization.leftAvatar = uri.toString();
options.uiCustomization.titleCenter = true;
options.sdkEvents = new SDKEvents();
options.sdkEvents.eventProcessFactory = new EventProcessFactory() {
@Override
public UnicornEventBase eventOf(int i) {
if (i == 5) {
return new RequestPermissionEvent();
} else {
return null;
}
}
};
// appKey 可以在七鱼管理系统->设置->App 接入 页面找到
Unicorn.init(context, XChatConstants.QI_YU_KF_KEY, options, new GlideImageLoader(context));
Unicorn.initSdk();
@@ -133,5 +148,4 @@ public class CustomerServerHelper {
Unicorn.logout();
isInit = false;
}
}

View File

@@ -0,0 +1,124 @@
package com.nnbc123.app.qiyukefu
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.Settings
import androidx.fragment.app.FragmentActivity
import com.chuhai.utils.ktx.asActivity
import com.nnbc123.app.R
import com.nnbc123.app.common.permission.PermissionHelper
import com.nnbc123.app.ui.widget.dialog.CommonTipDialog
import com.nnbc123.app.ui.widget.dialog.RequestPermissionPromptDialog
import com.nnbc123.library.utils.ResUtil
import com.qiyukf.unicorn.api.event.EventCallback
import com.qiyukf.unicorn.api.event.UnicornEventBase
import com.qiyukf.unicorn.api.event.entry.RequestPermissionEventEntry
import com.tbruyelle.rxpermissions2.RxPermissions
/**
* Created by Max on 2024/1/4 11:10
* Desc:
**/
class RequestPermissionEvent : UnicornEventBase<RequestPermissionEventEntry> {
override fun onEvent(
p0: RequestPermissionEventEntry?,
p1: Context?,
p2: EventCallback<RequestPermissionEventEntry>?
) {
val tips = getPermissionTips(p0?.scenesType)
val activity = (p1?.asActivity() as? FragmentActivity)
val perms = p0?.permissionList?.toTypedArray()
if (RequestPermissionPromptDialog.isNeedPrompt()
&& tips != null
&& activity != null
&& perms != null
) {
val rxPermissions = RxPermissions(activity)
if (PermissionHelper.isAllGender(rxPermissions, * perms)) {
p2?.onNotPorcessEvent()
} else {
RequestPermissionPromptDialog(p1, tips).show()
val d = rxPermissions.request(*perms).subscribe({ aBoolean: Boolean? ->
RequestPermissionPromptDialog.dismissCurrentDialog()
if (aBoolean == true) {
p2?.onProcessEventSuccess(p0)
} else {
showDeniedTips(p1, tips)
p2?.onInterceptEvent()
}
}) { obj: Throwable ->
RequestPermissionPromptDialog.dismissCurrentDialog()
obj.printStackTrace()
p2?.onNotPorcessEvent()
}
}
} else {
p2?.onNotPorcessEvent()
}
}
override fun onDenyEvent(p0: Context?, p1: RequestPermissionEventEntry?): Boolean {
if (p0 == null) {
return super.onDenyEvent(p0, p1)
}
val tips = getPermissionTips(p1?.scenesType)
return if (tips != null) {
showDeniedTips(p0, tips)
true
} else {
super.onDenyEvent(p0, p1)
}
}
/**
* 获取场景对应的权限提示信息不需要提示的权限返回null
*/
private fun getPermissionTips(scenesType: Int?): String? {
when (scenesType) {
RequestPermissionEventEntry.SCENES_TAKE_AUDIO -> {
return ResUtil.getString(R.string.permission_denied_tips_mic)
}
RequestPermissionEventEntry.SCENES_SELECT_MEDIA,
RequestPermissionEventEntry.SCENES_TAKE_VIDEO,
RequestPermissionEventEntry.SCENES_SAVE_IMAGE,
RequestPermissionEventEntry.SCENES_SAVE_VIDEO,
RequestPermissionEventEntry.SCENES_SELECT_VIDEO,
RequestPermissionEventEntry.SCENES_SELECT_FILE,
RequestPermissionEventEntry.SCENES_SELECT_IMAGE,
RequestPermissionEventEntry.SCENES_TAKE_PHOTO,
RequestPermissionEventEntry.SCENES_VIDEO_CHAT -> {
return ResUtil.getString(R.string.permission_denied_tips_image)
}
else -> {
return null
}
}
}
private fun showDeniedTips(context: Context, message: String) {
CommonTipDialog(context).apply {
setTipMsg(message)
setOkText("去设置")
setOnActionListener(
object : CommonTipDialog.OnActionListener {
override fun onOk() {
//同意跳到应用详情页面
val packageUri =
Uri.parse("package:${context.packageName}")
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
packageUri
)
(context as? Activity)?.startActivityForResult(
intent, 0
)
}
}
)
}.show()
}
}

View File

@@ -2,17 +2,18 @@ package com.nnbc123.app.ui.im.fragment;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -20,6 +21,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;
import androidx.lifecycle.Lifecycle;
import com.netease.nim.uikit.api.UIKitOptions;
@@ -53,12 +55,15 @@ import com.netease.nimlib.sdk.robot.model.NimRobotInfo;
import com.netease.nimlib.sdk.robot.model.RobotAttachment;
import com.netease.nimlib.sdk.robot.model.RobotMsgType;
import com.nnbc123.app.R;
import com.nnbc123.app.common.permission.PermissionHelper;
import com.nnbc123.app.common.widget.OriginalDrawStatusClickSpan;
import com.nnbc123.app.ui.im.GreetPresenter;
import com.nnbc123.app.ui.im.MessageListPanelEx;
import com.nnbc123.app.ui.im.chat.MVHChatterBoxStart;
import com.nnbc123.app.ui.im.model.IMCustomModel;
import com.nnbc123.app.ui.webview.CommonWebViewActivity;
import com.nnbc123.app.ui.widget.dialog.CommonTipDialog;
import com.nnbc123.app.ui.widget.dialog.RequestPermissionPromptDialog;
import com.nnbc123.app.utils.PushMessageHandler;
import com.nnbc123.core.UriProvider;
import com.nnbc123.core.auth.AuthModel;
@@ -70,6 +75,7 @@ import com.nnbc123.core.im.custom.bean.ImTipAttachment;
import com.nnbc123.core.room.event.MessageSizeEvent;
import com.nnbc123.core.statistic.StatisticManager;
import com.nnbc123.core.statistic.protocol.StatisticsProtocol;
import com.nnbc123.library.utils.ResUtil;
import com.nnbc123.library.utils.SingleToastUtil;
import com.nnbc123.library.utils.config.BasicConfig;
import com.tbruyelle.rxpermissions2.RxPermissions;
@@ -87,7 +93,6 @@ import java.util.Map;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
/**
@@ -228,7 +233,7 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
IMMessage anchor = (IMMessage) getArguments().getSerializable(Extras.EXTRA_ANCHOR);
customization = (SessionCustomization) getArguments().getSerializable(Extras.EXTRA_CUSTOMIZATION);
Container container = new Container(getActivity(), sessionId, sessionType, this);
Container container = new Container(getActivity(), sessionId, sessionType, this, this::requestPermission);
if (messageListPanel == null) {
messageListPanel = new MessageListPanelEx(container, rootView, anchor, false, false);
@@ -275,13 +280,10 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
GreetPresenter greetPresenter = new GreetPresenter(sessionId);
if (greetPresenter.isCanSendGreet()) {
greetDisposable = greetPresenter.greetMsgGetOne(AuthModel.get().getCurrentUid(), toUid)
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
if (!TextUtils.isEmpty(s)) {
sendMessage(MessageBuilder.createTextMessage(container.account,
container.sessionType, s));
}
.subscribe(s -> {
if (!TextUtils.isEmpty(s)) {
sendMessage(MessageBuilder.createTextMessage(container.account,
container.sessionType, s));
}
});
}
@@ -322,6 +324,24 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
}
private void requestPermission(Consumer<Boolean> consumer, String tips, String... perms) {
Context context = getContext();
if (context != null && RequestPermissionPromptDialog.Companion.isNeedPrompt()
&& !PermissionHelper.INSTANCE.isAllGender(rxPermissions, perms)) {
new RequestPermissionPromptDialog(context, tips).show();
}
Disposable disposable = rxPermissions.request(perms).subscribe(aBoolean -> {
RequestPermissionPromptDialog.Companion.dismissCurrentDialog();
if (!aBoolean) {
showPermissionDeniedTipsDialog(tips);
}
if (consumer != null) {
consumer.accept(aBoolean);
}
}, Throwable::printStackTrace);
compositeDisposable.add(disposable);
}
/**
* ********************** implements ModuleProxy *********************
*/
@@ -605,18 +625,48 @@ public class MessageFragment extends TFragment implements ModuleProxy, MessageLi
@Subscribe(threadMode = ThreadMode.MAIN)
@SuppressLint("CheckResult")
public void onNimAudioChatEvent(NimAudioChatEvent event) {
checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
String[] perms = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO)
Manifest.permission.RECORD_AUDIO};
String tips = ResUtil.getString(R.string.permission_denied_tips_mic);
if (RequestPermissionPromptDialog.Companion.isNeedPrompt()
&& !PermissionHelper.INSTANCE.isAllGender(rxPermissions, perms)) {
new RequestPermissionPromptDialog(requireContext(), tips).show();
}
checkPermission(perms)
.subscribe(result -> {
RequestPermissionPromptDialog.Companion.dismissCurrentDialog();
if (result) {
event.getSuccess().accept(result);
} else {
SingleToastUtil.showToast(getString(R.string.ask_again));
showPermissionDeniedTipsDialog(tips);
}
});
}
private void showPermissionDeniedTipsDialog(String message) {
CommonTipDialog mPrivacyDialog = new CommonTipDialog(getContext());
mPrivacyDialog.setTipMsg(message);
mPrivacyDialog.setOkText("去设置");
mPrivacyDialog.setOnActionListener(
new CommonTipDialog.OnActionListener() {
@Override
public void onOk() {
//同意跳到应用详情页面
Uri packageUri = Uri.parse("package:" + getContext().getPackageName());
Intent intent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
packageUri
);
startActivityForResult(
intent, 0
);
}
}
);
mPrivacyDialog.show();
}
@Subscribe(threadMode = ThreadMode.MAIN)
@SuppressLint("CheckResult")
public void onNimImageActionEvent(NimImageActionEvent event) {

View File

@@ -28,6 +28,7 @@ import com.nnbc123.app.ui.login.ModifyInfoActivity
import com.nnbc123.app.ui.user.UserPhotoAdapter.ImageClickListener
import com.nnbc123.app.ui.utils.ImageLoadUtils
import com.nnbc123.app.ui.widget.dialog.CommonTipDialog
import com.nnbc123.app.ui.widget.dialog.RequestPermissionPromptDialog
import com.nnbc123.app.utils.RegexUtil
import com.nnbc123.core.auth.AuthModel
import com.nnbc123.core.file.FileModel
@@ -40,6 +41,7 @@ import com.nnbc123.library.common.photo.PhotoProviderNew
import com.nnbc123.library.common.util.PhotoCompressCallback
import com.nnbc123.library.common.util.PhotoCompressUtil
import com.nnbc123.library.easypermisssion.EasyPermissions
import com.nnbc123.library.utils.ResUtil
import com.nnbc123.library.utils.TimeUtils
import com.sleepbot.datetimepicker.time.RadialPickerLayout
import com.sleepbot.datetimepicker.time.TimePickerDialog
@@ -276,6 +278,7 @@ class UserInfoModifyActivity : BaseViewBindingActivity<ActivityUserInfoModifyBin
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
if (requestCode == PERMISSION_CODE_STORAGE) {
RequestPermissionPromptDialog.dismissCurrentDialog()
val requestTip = "为了能正常加载您本地的文件内容,请前往应用权限设置界面打开存储空间权限。"
val mPrivacyDialog = CommonTipDialog(context)
mPrivacyDialog.setTipMsg(requestTip)
@@ -307,12 +310,19 @@ class UserInfoModifyActivity : BaseViewBindingActivity<ActivityUserInfoModifyBin
}
private fun checkStoragePermission() {
RequestPermissionPromptDialog.dismissCurrentDialog()
if (!EasyPermissions.hasPermissions(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
) {
if (RequestPermissionPromptDialog.isNeedPrompt()) {
RequestPermissionPromptDialog(
this,
ResUtil.getString(R.string.permission_denied_tips_image)
).show()
}
EasyPermissions.requestPermissions(
this,
"请您再次考虑授予存储空间权限,否则将无法正常加载您本地的文件内容。",

View File

@@ -28,6 +28,7 @@ import com.nnbc123.app.takephoto.compress.CompressConfig
import com.nnbc123.app.ui.user.UserModifyPhotosAdapter.PhotoItemClickListener
import com.nnbc123.app.ui.utils.ImageLoadUtils
import com.nnbc123.app.ui.widget.dialog.CommonTipDialog
import com.nnbc123.app.ui.widget.dialog.RequestPermissionPromptDialog
import com.nnbc123.app.utils.RegexUtil
import com.nnbc123.core.file.FileModel
import com.nnbc123.core.user.UserModel
@@ -39,6 +40,7 @@ import com.nnbc123.library.common.photo.PhotoProviderNew
import com.nnbc123.library.common.util.PhotoCompressCallback
import com.nnbc123.library.common.util.PhotoCompressUtil
import com.nnbc123.library.easypermisssion.EasyPermissions
import com.nnbc123.library.utils.ResUtil
import com.nnbc123.library.utils.file.JXFileUtils
import com.orhanobut.logger.Logger
import com.trello.rxlifecycle3.android.ActivityEvent
@@ -225,6 +227,7 @@ class UserModifyPhotosActivity : TakePhotoActivity(), PhotoItemClickListener,
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
if (requestCode == PERMISSION_CODE_STORAGE) {
RequestPermissionPromptDialog.dismissCurrentDialog()
val requestTip = "为了能正常加载您本地的文件内容,请前往应用权限设置界面打开存储空间权限。"
val mPrivacyDialog = CommonTipDialog(context)
mPrivacyDialog.setTipMsg(requestTip)
@@ -256,12 +259,19 @@ class UserModifyPhotosActivity : TakePhotoActivity(), PhotoItemClickListener,
}
private fun checkStoragePermission() {
RequestPermissionPromptDialog.dismissCurrentDialog()
if (!EasyPermissions.hasPermissions(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
) {
if (RequestPermissionPromptDialog.isNeedPrompt()) {
RequestPermissionPromptDialog(
this,
ResUtil.getString(R.string.permission_denied_tips_image)
).show()
}
EasyPermissions.requestPermissions(
this,
"请您再次考虑授予存储空间权限,否则将无法正常加载您本地的文件内容。",

View File

@@ -7,8 +7,9 @@ import android.util.Log;
import android.webkit.JavascriptInterface;
import com.alibaba.fastjson.JSONObject;
import com.chuhai.utils.MetaDataUtils;
import com.nnbc123.core.Constants;
import com.orhanobut.logger.Logger;
import com.tencent.vasdolly.helper.ChannelReaderUtil;
import com.nnbc123.app.application.XChatApplication;
import com.nnbc123.xchat_android_constants.XChatConstants;
import com.nnbc123.library.utils.AppUtils;
@@ -88,7 +89,7 @@ public class SimpleJSInterface {
@JavascriptInterface
public String getChannel() {
String channel;
channel = ChannelReaderUtil.getChannel(XChatApplication.instance());
channel = MetaDataUtils.INSTANCE.getStringData(Constants.CHANNEL_KEY, XChatApplication.instance());
if (TextUtils.isEmpty(channel)) {
channel = "official";
}

View File

@@ -0,0 +1,70 @@
package com.nnbc123.app.ui.widget.dialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.nnbc123.app.R
import com.nnbc123.library.utils.config.BasicConfig
/**
* Created by Max on 2024/1/8 10:06
* Desc:申请权限提示
**/
class RequestPermissionPromptDialog(context: Context, private val message: String) :
Dialog(context, R.style.dialog_full_width), LifecycleEventObserver {
companion object {
private var currentDialog: RequestPermissionPromptDialog? = null
fun dismissCurrentDialog() {
currentDialog?.dismiss()
currentDialog = null
}
/**
* 是否需要展示权限申请说明
*/
fun isNeedPrompt(): Boolean {
return (BasicConfig.INSTANCE.channel == "huawei")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
currentDialog = this
val window = window
if (window != null) {
val lps = window.attributes
lps.gravity = Gravity.TOP
lps.verticalMargin = 0f
lps.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
window.attributes = lps
}
setCanceledOnTouchOutside(false)
setContentView(R.layout.dialog_request_permission_prompt)
val rootView = findViewById<View>(R.id.layout_root)
// 权限已被拒时再申请权限会立即回调结果,这个弹窗看起来闪一下就没了,优化这个体验:延迟可见
rootView?.animate()?.alpha(1f)?.setStartDelay(200)?.start()
val messageView = findViewById<TextView>(R.id.tv_message)
messageView?.text = message
(ownerActivity as? LifecycleOwner)?.lifecycle?.addObserver(this)
}
override fun dismiss() {
currentDialog = null
(ownerActivity as? LifecycleOwner)?.lifecycle?.removeObserver(this)
super.dismiss()
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_DESTROY) {
this@RequestPermissionPromptDialog.dismiss()
}
}
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginTop="5dp"
android:alpha="0"
android:background="@drawable/shape_white_8dp_round"
android:paddingHorizontal="28dp"
android:paddingVertical="14dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="权限使用说明:"
android:textColor="#2B2D33"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:textColor="#696D7A"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="@id/tv_title"
tools:text="MESSAGEMESSA" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -97,7 +97,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/dp_18"
android:text="玩伴推荐"
android:text="玩伴"
android:textColor="#2B2D33"
android:textSize="@dimen/dp_16"
android:textStyle="bold"

View File

@@ -147,7 +147,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_19"
android:layout_marginTop="@dimen/dp_12"
android:text="热门推荐"
android:text="热门"
android:textColor="#2B2D33"
android:textSize="@dimen/dp_16"
android:textStyle="bold"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -987,5 +987,6 @@
<string name="gang_up_invite">开黑邀请</string>
<string name="Black_duration">开黑时长(局):</string>
<string name="diamond_inning">%d钻/局</string>
<string name="permission_denied_tips_mic">为了实现连麦及语音输入等功能,请您允许应用向您获取“麦克风”权限</string>
<string name="permission_denied_tips_image">访问你的本地内容,以能正常使用图片上传、视频发送等应用功能</string>
</resources>

View File

@@ -16,7 +16,6 @@
</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor" tools:targetApi="lollipop">@color/transparent</item>
</style>
@@ -126,6 +125,19 @@
<item name="android:backgroundDimAmount">0.5</item>
</style>
<style name="dialog_full_width" parent="android:Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowMinWidthMajor">100%</item>
<item name="android:windowMinWidthMinor">100%</item>
</style>
<style name="top_dialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowIsFloating">false</item>
<item name="windowActionBar">false</item>

View File

@@ -3,11 +3,13 @@ package com.nnbc123.app.community.publish.view;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.provider.Settings;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
@@ -21,8 +23,13 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.google.android.flexbox.FlexboxLayout;
import com.hjq.toast.ToastUtils;
import com.netease.nim.uikit.StatusBarUtil;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.nnbc123.app.common.permission.PermissionHelper;
import com.nnbc123.app.ui.widget.dialog.CommonTipDialog;
import com.nnbc123.app.ui.widget.dialog.RequestPermissionPromptDialog;
import com.nnbc123.library.utils.ResUtil;
import com.trello.rxlifecycle3.android.ActivityEvent;
import com.nnbc123.app.R;
import com.nnbc123.app.base.BaseMvpActivity;
@@ -191,26 +198,36 @@ public class PublishActivity extends BaseMvpActivity<IPublishView, PublishPresen
imageAdapter.setOnItemClickListener((adapter, view, position) -> {
PublishItem item = imageShowList.get(position);
if (item.isAddItem()) {
checkPermission(() -> {
CaptureStrategy captureStrategy = new CaptureStrategy(true, context.getPackageName() + ".fileprovider",
BasicConfig.INSTANCE.getImageDir().getAbsolutePath());
int maxCanSelect = 9 - uploadList.size();
Matisse.from(PublishActivity.this)
.choose(MimeType.ofImage())
.showSingleMediaType(true)
.capture(true)
.spanCount(4)
.captureStrategy(captureStrategy)
.countable(true)
.maxSelectable(maxCanSelect)
.originalEnable(false)
.maxOriginalSize(10)
.imageEngine(new Glide4Engine())
.setType(2)
.setOriginalImagee(isOriginalImage)
.forResult(ConstantValue.CODE_CHOOSE_PHOTO);
}, R.string.ask_storage, Manifest.permission.READ_EXTERNAL_STORAGE);
String tips = ResUtil.getString(R.string.permission_denied_tips_image);
String permission = Manifest.permission.READ_EXTERNAL_STORAGE;
if (RequestPermissionPromptDialog.Companion.isNeedPrompt()
&& !PermissionHelper.INSTANCE.isAllGender(rxPermissions, permission)) {
new RequestPermissionPromptDialog(this, tips).show();
}
checkPermission((aBoolean) -> {
RequestPermissionPromptDialog.Companion.dismissCurrentDialog();
if (aBoolean) {
CaptureStrategy captureStrategy = new CaptureStrategy(true, context.getPackageName() + ".fileprovider",
BasicConfig.INSTANCE.getImageDir().getAbsolutePath());
int maxCanSelect = 9 - uploadList.size();
Matisse.from(PublishActivity.this)
.choose(MimeType.ofImage())
.showSingleMediaType(true)
.capture(true)
.spanCount(4)
.captureStrategy(captureStrategy)
.countable(true)
.maxSelectable(maxCanSelect)
.originalEnable(false)
.maxOriginalSize(10)
.imageEngine(new Glide4Engine())
.setType(2)
.setOriginalImagee(isOriginalImage)
.forResult(ConstantValue.CODE_CHOOSE_PHOTO);
} else {
showPermissionDeniedDialog(tips);
}
}, permission);
} else {
BigPhotoActivity.startCanDelete(PublishActivity.this, (ArrayList<CustomItem>) uploadList,
position, new PagerOption().setDelete(true));
@@ -230,6 +247,29 @@ public class PublishActivity extends BaseMvpActivity<IPublishView, PublishPresen
updateImagesData();
}
private void showPermissionDeniedDialog(String tips){
CommonTipDialog mPrivacyDialog = new CommonTipDialog(context);
mPrivacyDialog.setTipMsg(tips);
mPrivacyDialog.setOkText("去设置");
mPrivacyDialog.setOnActionListener(
new CommonTipDialog.OnActionListener() {
@Override
public void onOk() {
//同意跳到应用详情页面
Uri packageUri = Uri.parse("package:" + getPackageName());
Intent intent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
packageUri
);
startActivityForResult(
intent, 0
);
}
}
);
mPrivacyDialog.show();
}
private void updateImagesData() {
List<PublishItem> tmp = new ArrayList<>();
for (int i = 0; i < uploadList.size(); i++) {

View File

@@ -25,7 +25,7 @@ buildscript {
// android 资源混淆插件
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
classpath 'com.tencent.vasdolly:plugin:3.0.3'
// classpath 'com.tencent.vasdolly:plugin:3.0.3'
classpath "com.mob.sdk:MobSDK:2018.0319.1724"
classpath "com.github.qq549631030:android-junk-code:1.0.7"
}

View File

@@ -13,6 +13,7 @@ import java.util.List;
* Created by Administrator on 2017/11/9.
*/
public class Constants {
public static final String CHANNEL_KEY = "CHANNEL";
public static final String ERBAN_DIR_NAME = XChatConstants.XCHAT_DIR_NAME;
public static final String nimAppKey = Env.isDebug() ?
XChatConstants.NIM_KEY_DEBUG : XChatConstants.NIM_KEY_RELEASE;

View File

@@ -23,7 +23,6 @@ with_flutter_aar=true
with_jenkins=false
only_arm64=false
channel_file=channel.txt
COMPILE_SDK_VERSION=32
MIN_SDK_VERSION=21

View File

@@ -0,0 +1,55 @@
package com.chuhai.utils
import android.content.Context
import android.content.pm.PackageManager
import android.os.Bundle
import android.text.TextUtils
/**
* MetaData工具
* @author Max
* @date 2019-11-26.
*/
object MetaDataUtils {
/**
* 获取元数据
* @param context 上下文
*/
fun getMetaData(context: Context? = AppUtils.getApp()): Bundle? {
if (context == null) {
return null
}
try {
val packageManager = context.packageManager ?: return null
val applicationInfo = packageManager.getApplicationInfo(
context.packageName,
PackageManager.GET_META_DATA
)
return applicationInfo.metaData
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
/**
* 获取布尔值
*/
fun getBooleanData(key: String, context: Context? = AppUtils.getApp()): Boolean? {
return getMetaData(context)?.getBoolean(key)
}
/**
* 获取字符串
*/
fun getStringData(key: String, context: Context? = AppUtils.getApp()): String? {
return getMetaData(context)?.getString(key)
}
/**
* 获取Int
*/
fun getIntData(key: String, context: Context? = AppUtils.getApp()): Int? {
return getMetaData(context)?.getInt(key)
}
}

View File

@@ -1,9 +1,9 @@
package com.netease.nim.uikit.business.session.actions
import android.Manifest
import android.content.Intent
import android.text.TextUtils
import com.netease.nim.uikit.R
import com.netease.nim.uikit.business.session.helper.SendImageHelper
import com.nnbc123.library.common.application.BaseApp
import com.nnbc123.library.common.base.BaseDialogFragment
import com.nnbc123.library.common.photo.PhotoProviderNew
@@ -29,7 +29,18 @@ abstract class PickImageActionNew protected constructor(
protected abstract fun onPicked(file: File)
override fun onClick() {
checkStoragePermission()
container.permissionProxy?.let {
it.requestPermission(
{ result ->
if (result) {
checkStoragePermission()
}
},
"访问你的本地内容,以能正常使用图片上传、视频发送等应用功能",
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
} ?: checkStoragePermission()
}
private fun checkStoragePermission() {

View File

@@ -12,6 +12,7 @@ public class Container {
public final String account;
public final SessionTypeEnum sessionType;
public final ModuleProxy proxy;
public PermissionProxy permissionProxy;
public Container(Activity activity, String account, SessionTypeEnum sessionType, ModuleProxy proxy) {
this.activity = activity;
@@ -19,4 +20,12 @@ public class Container {
this.sessionType = sessionType;
this.proxy = proxy;
}
public Container(Activity activity, String account, SessionTypeEnum sessionType, ModuleProxy proxy, PermissionProxy permissionProxy) {
this.activity = activity;
this.account = account;
this.sessionType = sessionType;
this.proxy = proxy;
this.permissionProxy = permissionProxy;
}
}

View File

@@ -0,0 +1,17 @@
package com.netease.nim.uikit.business.session.module
import androidx.core.util.Consumer
/**
* Created by Max on 2024/1/4 15:21
* Desc:
**/
interface PermissionProxy {
/**
* 申请权限
* @param consumer
* @param perms 权限列表
*/
fun requestPermission(consumer: Consumer<Boolean>, tips: String, vararg perms: String)
}

View File

@@ -11,6 +11,8 @@ import android.view.inputmethod.InputMethodManager;
import com.netease.nim.uikit.common.activity.UI;
import com.netease.nim.uikit.common.util.log.LogUtil;
import io.reactivex.disposables.CompositeDisposable;
public abstract class TFragment extends Fragment {
private static final Handler handler = new Handler();
@@ -18,6 +20,8 @@ public abstract class TFragment extends Fragment {
private boolean destroyed;
protected CompositeDisposable compositeDisposable = new CompositeDisposable();
protected final boolean isDestroyed() {
return destroyed;
}
@@ -42,7 +46,7 @@ public abstract class TFragment extends Fragment {
super.onDestroy();
LogUtil.ui("fragment: " + getClass().getSimpleName() + " onDestroy()");
compositeDisposable.dispose();
destroyed = true;
}