diff --git a/appbase/build.properties b/appbase/build.properties index e17b41c..66997c3 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:23:34 HKT 2026 +#Tue Jan 20 12:51:34 GMT 2026 stageCount=5 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.4 -buildCount=0 +buildCount=38 baseBetaVersion=15.15.5 diff --git a/libappbase/build.properties b/libappbase/build.properties index d1d8227..66997c3 100644 --- a/libappbase/build.properties +++ b/libappbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Jan 13 03:23:17 HKT 2026 +#Tue Jan 20 12:51:34 GMT 2026 stageCount=5 libraryProject=libappbase baseVersion=15.15 publishVersion=15.15.4 -buildCount=0 +buildCount=38 baseBetaVersion=15.15.5 diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java new file mode 100644 index 0000000..3749c3b --- /dev/null +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/dialogs/SignGetDialog.java @@ -0,0 +1,128 @@ +package cc.winboll.studio.libappbase.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.widget.EditText; +import android.widget.TextView; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.R; +import cc.winboll.studio.libappbase.ToastUtils; +import cc.winboll.studio.libappbase.utils.APPUtils; +import cc.winboll.studio.libappbase.utils.SignGetUtils; + +/** + * @Describe 签名显示+正版校验对话框 + * @Author 豆包&ZhanGSKen + * @Date 2026/01/20 21:20:00 + * @LastEditTime 2026/01/21 11:00:00 + */ +public class SignGetDialog extends Dialog { + private static final String TAG = "SignGetDialog"; + private EditText etSignFingerprint; + private TextView tvAuthResult; + private Context mContext; + + public SignGetDialog(Context context) { + super(context, R.style.DialogStyle); // 适配默认对话框样式 + this.mContext = context; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_sign_get); // 绑定xml布局 + setCancelable(true); // 点击外部可关闭 + initView(); + initSignAndCheck(); // 获取签名+正版校验 + } + + private void initView() { + etSignFingerprint = findViewById(R.id.et_sign_fingerprint); + tvAuthResult = findViewById(R.id.tv_auth_result); + // 输入框只读,方便复制 + etSignFingerprint.setEnabled(false); + } + + // 核心:获取签名+调用APPUtils校验 + private void initSignAndCheck() { + // 1. 获取当前应用签名 + String sign = getCurrentSign(); + if (sign == null) { + etSignFingerprint.setText("签名获取失败"); + } else { + // 签名字符串转0/1 bit数组(每2个bit加空格,每16位换行,下一行无前置空格) + String bitArrayStr = convertSignToBitArrayWithWrap(sign); + etSignFingerprint.setText(bitArrayStr); + } + LogUtils.d(TAG, "当前应用签名:" + sign); + + // 2. 正版校验+显示结果 + APPUtils.checkAppValid(mContext); + boolean isOfficial = isSignValid(); + if (isOfficial) { + ToastUtils.show("这是正版的WinBoLL应用,请放心使用。"); + tvAuthResult.setTextColor(Color.BLUE); + tvAuthResult.setText("这是正版的WinBoLL应用,请放心使用。"); + } else { + ToastUtils.show("您使用的可能不是正版的 WinBoLL 应用。"); + tvAuthResult.setTextColor(Color.RED); + tvAuthResult.setText("您使用的可能不是正版的 WinBoLL 应用。"); + } + } + + // 核心修改:签名字符串转0/1 bit数组(每2个bit加空格,每16位换行,下一行无前置空格) + private String convertSignToBitArrayWithWrap(String signStr) { + StringBuilder bitBuilder = new StringBuilder(); + // 1. 字符转8位bit + for (char c : signStr.toCharArray()) { + String bit8 = String.format("%8s", Integer.toBinaryString(c)).replace(' ', '0'); + bitBuilder.append(bit8); + } + String fullBitStr = bitBuilder.toString(); + + // 2. 按16位分组,组内每2个bit加空格(避免换行后带空格) + StringBuilder finalBuilder = new StringBuilder(); + int groupSize = 16; // 每组16个bit + for (int i = 0; i < fullBitStr.length(); i += groupSize) { + // 截取16位bit为一组 + int end = Math.min(i + groupSize, fullBitStr.length()); + String group = fullBitStr.substring(i, end); + + // 组内每2个bit加空格 + StringBuilder groupWithSpace = new StringBuilder(); + for (int j = 0; j < group.length(); j++) { + groupWithSpace.append(group.charAt(j)); + if ((j + 1) % 2 == 0 && j != group.length() - 1) { + groupWithSpace.append(" "); + } + } + + // 添加组到最终结果,每组后换行(最后一组不换行) + finalBuilder.append(groupWithSpace); + if (end < fullBitStr.length()) { + finalBuilder.append("\n"); + } + } + return finalBuilder.toString(); + } + + // 获取签名(复用SignGetUtils逻辑,避免重复代码) + private String getCurrentSign() { + try { + return SignGetUtils.getSignStr(mContext); // 复用工具类逻辑 + } catch (Exception e) { + LogUtils.e(TAG, "获取签名失败", e); + return null; + } + } + + // 校验签名是否合法(匹配APPUtils目标签名) + private boolean isSignValid() { + String currentSign = getCurrentSign(); + String targetSign = APPUtils.TARGET_SIGN_FINGERPRINT; // 取APPUtils目标签名 + return currentSign != null && targetSign != null && currentSign.equals(targetSign); + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java new file mode 100644 index 0000000..306f78a --- /dev/null +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/APPUtils.java @@ -0,0 +1,78 @@ +package cc.winboll.studio.libappbase.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.util.Base64; +import cc.winboll.studio.libappbase.LogUtils; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/20 19:17 + * @Describe APPUtils 应用包名、签名校验工具类 + */ +public class APPUtils { + + public static final String TAG = "APPUtils"; + // 目标应用签名指纹(BASE64格式,自行替换为你的合法指纹) + //public static final String TARGET_SIGN_FINGERPRINT = "你的应用签名SHA1指纹BASE64值"; + public static final String TARGET_SIGN_FINGERPRINT = "bMArVdXE4ZZo42vS9e/kXE63MkE="; + // 目标应用包名(自行替换为你的应用包名) + private static final String TARGET_PACKAGE_NAME = "cc.winboll.studio.你的应用包名"; + + /** + * 检查应用包名+签名指纹合法性,不匹配打日志,匹配无操作 + * @param context 上下文 + */ + public static void checkAppValid(Context context) { + if (context == null) { + LogUtils.w(TAG, "checkAppValid: context为空,跳过校验"); + return; + } + // 1. 校验包名 + String currentPkg = context.getPackageName(); + LogUtils.d(TAG, "checkAppValid: 当前应用包名=" + currentPkg + ",目标包名=" + TARGET_PACKAGE_NAME); + if (!TARGET_PACKAGE_NAME.equals(currentPkg)) { + LogUtils.e(TAG, "checkAppValid: 应用包名不匹配,非法环境"); + return; + } + // 2. 校验签名指纹 + String currentSign = getAppSignFingerprint(context); + LogUtils.d(TAG, "checkAppValid: 当前应用签名指纹=" + currentSign + ",目标指纹=" + TARGET_SIGN_FINGERPRINT); + if (currentSign == null || !TARGET_SIGN_FINGERPRINT.equals(currentSign)) { + LogUtils.e(TAG, "checkAppValid: 应用签名指纹不匹配,非法环境"); + } + } + + /** + * 获取当前应用签名SHA1指纹(BASE64编码,适配Java7) + * @param context 上下文 + * @return 签名指纹字符串,失败返回null + */ + private static String getAppSignFingerprint(Context context) { + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + if (signatures == null || signatures.length == 0) { + LogUtils.w(TAG, "getAppSignFingerprint: 未获取到应用签名"); + return null; + } + // SHA1摘要 + BASE64编码,和目标指纹格式统一 + MessageDigest md = MessageDigest.getInstance("SHA1"); + md.update(signatures[0].toByteArray()); + return Base64.encodeToString(md.digest(), Base64.NO_WRAP); + } catch (PackageManager.NameNotFoundException e) { + LogUtils.e(TAG, "getAppSignFingerprint: 包名未找到", e); + } catch (NoSuchAlgorithmException e) { + LogUtils.e(TAG, "getAppSignFingerprint: 不支持SHA1算法", e); + } catch (Exception e) { + LogUtils.e(TAG, "getAppSignFingerprint: 获取签名异常", e); + } + return null; + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/SignGetUtils.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/SignGetUtils.java new file mode 100644 index 0000000..c3895c5 --- /dev/null +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/utils/SignGetUtils.java @@ -0,0 +1,71 @@ +package cc.winboll.studio.libappbase.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.util.Base64; +import cc.winboll.studio.libappbase.LogUtils; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/20 19:50 + * @Describe 获取应用签名指纹(SHA1+Base64,直接复制用) + */ +public class SignGetUtils { + private static final String TAG = "SignGetUtils"; + + /** + * 一键获取当前应用签名指纹(直接调用,看日志复制结果) + */ + public static void getCurrentAppSign(Context context) { + if (context == null) { + LogUtils.e(TAG, "context不能为空"); + return; + } + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + if (signatures == null || signatures.length == 0) { + LogUtils.e(TAG, "未获取到应用签名"); + return; + } + // 和APPUtils校验格式完全一致(SHA1+Base64 NO_WRAP) + MessageDigest md = MessageDigest.getInstance("SHA1"); + md.update(signatures[0].toByteArray()); + String signBase64 = Base64.encodeToString(md.digest(), Base64.NO_WRAP); + + // 关键日志:复制【】里的内容到APPUtils的TARGET_SIGN_FINGERPRINT + LogUtils.d(TAG, "当前应用包名:" + context.getPackageName()); + LogUtils.d(TAG, "当前应用签名指纹(直接复制):【" + signBase64 + "】"); + } catch (PackageManager.NameNotFoundException e) { + LogUtils.e(TAG, "获取签名失败:包名不存在", e); + } catch (NoSuchAlgorithmException e) { + LogUtils.e(TAG, "获取签名失败:不支持SHA1", e); + } catch (Exception e) { + LogUtils.e(TAG, "获取签名失败", e); + } + } + + // 新增:直接返回签名字符串,供对话框调用 + public static String getSignStr(Context context) { + if (context == null) return null; + try { + PackageManager pm = context.getPackageManager(); + PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + Signature[] signatures = pkgInfo.signatures; + if (signatures == null || signatures.length == 0) return null; + + MessageDigest md = MessageDigest.getInstance("SHA1"); + md.update(signatures[0].toByteArray()); + return Base64.encodeToString(md.digest(), Base64.NO_WRAP); + } catch (Exception e) { + LogUtils.e(TAG, "获取签名字符串失败", e); + return null; + } + } +} + diff --git a/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java b/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java index 60e7866..3c3892f 100644 --- a/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java +++ b/libappbase/src/main/java/cc/winboll/studio/libappbase/views/AboutView.java @@ -8,21 +8,22 @@ import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; - import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.R; import cc.winboll.studio.libappbase.ToastUtils; +import cc.winboll.studio.libappbase.dialogs.SignGetDialog; import cc.winboll.studio.libappbase.models.APPInfo; /** * @Describe AboutView 原生实现关于页面,无第三方依赖,适配API30,抽象通用功能控件(邮件/网页跳转) * @Author 豆包&ZhanGSKen * @Date 2026/01/11 12:23:00 - * @LastEditTime 2026/01/12 01:05:30 + * @LastEditTime 2026/01/20 20:45:00 */ public class AboutView extends LinearLayout { // 全局常量区(标识、回调标识) @@ -41,7 +42,6 @@ public class AboutView extends LinearLayout { private static final int PADDING_MID = 16; private static final int PADDING_SMALL = 8; private static final int ICON_SIZE = 48; - private static final int LINE_HEIGHT = 1; private static final int ITEM_ICON_SIZE = 24; // 成员属性区(按 核心依赖→业务配置→视图相关 归类排序,注释清晰) @@ -66,12 +66,19 @@ public class AboutView extends LinearLayout { private EditText metDevUserName; // 调试用户名输入框 private EditText metDevUserPassword; // 调试密码输入框 + // 视图绑定 + private ImageView ivAppIcon; + private TextView tvAppNameVersion; + private TextView tvAppDesc; + private LinearLayout llFunctionContainer; + // 构造方法区(按 参数从少到多 排序,适配 代码创建+XML引用 场景) public AboutView(Context context) { super(context); LogUtils.d(TAG, "AboutView(Context) 构造方法调用,代码创建视图场景"); this.mContext = context; initDefaultParams(); + initViewFromXml(); } public AboutView(Context context, APPInfo appInfo) { @@ -79,6 +86,7 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "AboutView(Context,APPInfo) 构造调用,入参APPInfo:" + (appInfo == null ? "null" : appInfo.getAppName())); this.mContext = context; this.mAPPInfo = appInfo; + initViewFromXml(); initAll(); } @@ -87,6 +95,7 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "AboutView(Context,AttributeSet) 构造调用,XML布局引用场景"); this.mContext = context; initDefaultParams(); + initViewFromXml(); } public AboutView(Context context, AttributeSet attrs, int defStyleAttr) { @@ -94,8 +103,45 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "AboutView(Context,AttributeSet,int) 构造调用,XML布局+样式配置,defStyleAttr:" + defStyleAttr); this.mContext = context; initDefaultParams(); + initViewFromXml(); } + // 核心:加载xml布局并绑定视图 +// private void initViewFromXml() { +// View.inflate(mContext, R.layout.layout_about_view, this); +// ivAppIcon = findViewById(R.id.iv_app_icon); +// tvAppNameVersion = findViewById(R.id.tv_app_name_version); +// tvAppDesc = findViewById(R.id.tv_app_desc); +// llFunctionContainer = findViewById(R.id.ll_function_container); +// LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); +// } + // 1. 新增视图绑定属性(加在原有视图属性后面) + private ImageButton ibSigngetdialog; + +// 2. 完善initViewFromXml方法,新增按钮绑定 + private void initViewFromXml() { + View.inflate(mContext, R.layout.layout_about_view, this); + ivAppIcon = findViewById(R.id.iv_app_icon); + tvAppNameVersion = findViewById(R.id.tv_app_name_version); + tvAppDesc = findViewById(R.id.tv_app_desc); + llFunctionContainer = findViewById(R.id.ll_function_container); + ibSigngetdialog = findViewById(R.id.ib_signgetdialog); // 新增按钮绑定 + setBtnClickListener(); // 新增绑定点击事件 + LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); + } + +// 3. 新增按钮点击事件方法(放在initViewFromXml下面即可) + private void setBtnClickListener() { + ibSigngetdialog.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + LogUtils.d(TAG, "签名获取按钮点击,弹出SignGetDialog"); + new SignGetDialog(mContext).show(); // 弹出对话框 + } + }); + } + + // 对外公开方法区(供外部调用,职责单一,注释明确) /** * 一站式初始化所有关于页逻辑,包含参数、信息、视图全流程初始化 @@ -106,10 +152,6 @@ public class AboutView extends LinearLayout { LogUtils.w(TAG, "initAll() 初始化终止:APPInfo 为 null,无法获取应用核心信息"); return; } - // 基础布局配置 - setOrientation(VERTICAL); - setPadding(dp2px(PADDING_MID), dp2px(PADDING_LARGE), dp2px(PADDING_MID), dp2px(PADDING_LARGE)); - setGravity(Gravity.CENTER_HORIZONTAL); // 按初始化流程执行,有序无冗余 initDefaultParams(); @@ -129,7 +171,7 @@ public class AboutView extends LinearLayout { public void setAPPInfoAndInit(APPInfo appInfo) { LogUtils.d(TAG, "setAPPInfoAndInit() 调用,传入新APPInfo:" + (appInfo == null ? "null" : appInfo.getAppName())); this.mAPPInfo = appInfo; - removeAllViews(); + llFunctionContainer.removeAllViews(); initAll(); LogUtils.d(TAG, "setAPPInfoAndInit() 应用信息重置+页面重构完成"); } @@ -141,7 +183,7 @@ public class AboutView extends LinearLayout { public void setAPPInfo(APPInfo appInfo) { LogUtils.d(TAG, "setAPPInfo() 调用,传入APPInfo:" + (appInfo == null ? "null" : appInfo.getAppName())); this.mAPPInfo = appInfo; - removeAllViews(); + llFunctionContainer.removeAllViews(); initAll(); } @@ -196,7 +238,7 @@ public class AboutView extends LinearLayout { LogUtils.d(TAG, "initAppVersionInfo() 获取版本号失败,默认赋值unknown", e); mszAppVersionName = "unknown"; } - mszCurrentAppPackageName = String.format("%s_%s.apk", mszAppAPKName, mszAppVersionName); + mszCurrentAppPackageName = String.format("%s_%s.apk", mszAppVersionName, mszAppVersionName); LogUtils.d(TAG, "initAppVersionInfo() 完成,版本号:" + mszAppVersionName + ",当前APK名:" + mszCurrentAppPackageName); } @@ -245,77 +287,37 @@ public class AboutView extends LinearLayout { } /** - * 核心视图组装:按 图标→应用信息→分割线→通用功能控件 顺序构建页面 + * 核心视图组装:赋值基础信息+添加功能项 */ private void initAboutPageView() { LogUtils.d(TAG, "initAboutPageView() 开始组装关于页视图"); - addAppIcon(); - addAppInfoDesc(); - addLineSeparator(); + // 基础信息赋值 + ivAppIcon.setImageResource(mnAppIcon); + tvAppNameVersion.setText(String.format("%s %s", mszAppName, mszAppVersionName)); + if (mszAppDescription.isEmpty()) { + tvAppDesc.setVisibility(GONE); + } else { + tvAppDesc.setVisibility(VISIBLE); + tvAppDesc.setText(mszAppDescription); + } // 通用功能控件:网页跳转类+邮件类,复用抽象控件 - addView(new WebJumpFunctionItemView(mContext, "WinBoLL 主页", WINBOLL_OFFICIAL_HOME, R.drawable.ic_winboll)); - addView(new EmailFunctionItemView(mContext, "联系邮箱", "WinBoLLStudio", R.drawable.ic_winboll)); + addFunctionView(new WebJumpFunctionItemView(mContext, "WinBoLL 主页", WINBOLL_OFFICIAL_HOME, R.drawable.ic_winboll)); + addFunctionView(new EmailFunctionItemView(mContext, "联系邮箱", "WinBoLLStudio", R.drawable.ic_winboll)); if (!mszHomePage.isEmpty()) { - addView(new WebJumpFunctionItemView(mContext, "应用APK下载地址", mszHomePage, R.drawable.ic_winboll)); + addFunctionView(new WebJumpFunctionItemView(mContext, "应用APK下载地址", mszHomePage, R.drawable.ic_winboll)); } if (!mszGitea.isEmpty()) { - addView(new WebJumpFunctionItemView(mContext, "应用Git源码地址", mszGitea, R.drawable.ic_winboll)); + addFunctionView(new WebJumpFunctionItemView(mContext, "应用Git源码地址", mszGitea, R.drawable.ic_winboll)); } LogUtils.d(TAG, "initAboutPageView() 视图组装完成,功能项加载完毕"); } - // 视图构建辅助方法区(基础视图组件) - /** - * 添加应用图标组件,居中展示 - */ - private void addAppIcon() { - ImageView ivIcon = new ImageView(mContext); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dp2px(ICON_SIZE), dp2px(ICON_SIZE)); - params.bottomMargin = dp2px(PADDING_MID); - ivIcon.setLayoutParams(params); - ivIcon.setImageResource(mnAppIcon); - ivIcon.setScaleType(ImageView.ScaleType.CENTER_CROP); - addView(ivIcon); - } - - /** - * 添加应用名称+版本号+描述信息组件,垂直居中展示 - */ - private void addAppInfoDesc() { - LinearLayout llDesc = new LinearLayout(mContext); - llDesc.setOrientation(VERTICAL); - llDesc.setGravity(Gravity.CENTER); - llDesc.setPadding(0, 0, 0, dp2px(PADDING_MID)); - - TextView tvAppName = new TextView(mContext); - tvAppName.setText(String.format("%s %s", mszAppName, mszAppVersionName)); - tvAppName.setTextSize(18); - tvAppName.setTextColor(mContext.getResources().getColor(R.color.gray_900)); - llDesc.addView(tvAppName); - - if (!mszAppDescription.isEmpty()) { - TextView tvDesc = new TextView(mContext); - tvDesc.setText(mszAppDescription); - tvDesc.setTextSize(14); - tvDesc.setTextColor(mContext.getResources().getColor(R.color.gray_500)); - tvDesc.setPadding(0, dp2px(PADDING_SMALL), 0, 0); - llDesc.addView(tvDesc); - } - addView(llDesc); - } - - /** - * 添加视图分割线,区分不同功能模块 - */ - private void addLineSeparator() { - View line = new View(mContext); - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dp2px(LINE_HEIGHT)); + // 添加功能项到容器 + private void addFunctionView(View view) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); params.topMargin = dp2px(PADDING_SMALL); - params.bottomMargin = dp2px(PADDING_MID); - line.setLayoutParams(params); - line.setBackgroundColor(mContext.getResources().getColor(R.color.gray_200)); - addView(line); + llFunctionContainer.addView(view, params); } // 工具方法区(通用工具+业务工具,静态优先,便于复用) diff --git a/libappbase/src/main/res/drawable/ic_key.xml b/libappbase/src/main/res/drawable/ic_key.xml new file mode 100644 index 0000000..4cea6c7 --- /dev/null +++ b/libappbase/src/main/res/drawable/ic_key.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libappbase/src/main/res/layout/dialog_sign_get.xml b/libappbase/src/main/res/layout/dialog_sign_get.xml new file mode 100644 index 0000000..f05f7aa --- /dev/null +++ b/libappbase/src/main/res/layout/dialog_sign_get.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + diff --git a/libappbase/src/main/res/layout/layout_about_view.xml b/libappbase/src/main/res/layout/layout_about_view.xml new file mode 100644 index 0000000..033c1b4 --- /dev/null +++ b/libappbase/src/main/res/layout/layout_about_view.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libappbase/src/main/res/values/styles.xml b/libappbase/src/main/res/values/styles.xml index 0dd004f..160ac17 100644 --- a/libappbase/src/main/res/values/styles.xml +++ b/libappbase/src/main/res/values/styles.xml @@ -11,5 +11,10 @@ #FF00B322 #FF000000 + +