开发至简网格的过程中,既要做服务侧开发,也要多端开发,服务侧分为JAVA服务侧、Android服务侧,端侧分为安卓、Windows,技术繁杂,碰到不少基本问题,全部记录在这里,便于以后查找。
顺便做个小广告,至简网格是一套端&云结合的开发框架,极大简化了服务侧与端侧开发,服务侧使用简单的json配置与sql、js脚本,就可以搞定95%以上的业务场景;端侧支持Android与Windows,本质是一个轻应用开发框架,用vue+quasar实现UI,使用极其简单。实现了几个业务代码,比如CRM、会员等,已在码云、CSDN开源。项目还在持续完善中,欢迎使用。
目录
1. 环境问题
1.1. AndroidStudio
1.1.1. 加入jar、aar的方法:
1.1.2. 模拟器路径权限
1.1.3. gradle安装
1.1.4. gradle问题
1.1.5. kotlin、gradle插件被禁用
1.1.6. Kotlin-android not found错误
1.1.7. 修改gradle配置
1.1.8. 打开logcat查看日志
1.1.9. 删除多余import
1.1.10. 修改checkstyle规则
1.1.11. 修改工程名称
1.1.12. adb覆盖安装
1.1.13. 导入样例工程时需要修改的地方
1.1.14 修改项目applicationId
1.2. 模拟器
1.2.1. 模拟器IP及外部访问
1.2.2. 进入模拟器命令行
1.3. 网络
1.3.1. 手机与PC之间网络不通
1.3.2. PC不能ping手机
1.3.3. 同局域网下手机访问PC
1.4. 小米手机
1.4.1. 小米手机,无法打开usb安装
1.4.2. 真机进入开发者模式
1.5. 华为或荣耀手机
1.5.1. 打开debug级别日志
1.6. iOS
1.6.1. IPhone webserver备忘
1.7. Eclipse
1.7.1. 更换包名
1.8. Gradle
1.8.1. asset下以下划线“_”开头的目录被忽略
1.9. Java
1.9.1. Windows安装GraalVm
1.9.2 Linux下安装GraalVm
1.10.Linux环境
1.10.1.创建用户
1.10.2.端口转发
1.10.3.图片验证码需要安装字体
2. 安卓开发问题
2.1. 权限
2.1.1. 应用权限设置
2.2. 底层
2.2.1. 动态加载dex插件
2.2.2. 实现禁止手动删除数据
2.2.3. 定义安全策略
2.2.4. 依赖了kotlin编写的库
2.3. 安全
2.3.1. 可信根加解密
2.3.2. 添加自签名根证书
2.4. JUnit测试
2.4.1. Android-Unit中无法写文件
2.4.2. 测试准备与清理
2.5. Logback日志
2.5.1. 配置中的属性
2.5.2. DATA_DIR等内置属性未定义
2.6. 版本发布
2.6.1. 应用签名
2.6.2. 图标不更新
3. C#开发问题
3.1. 目录权限
3.2. DEBUG宏
3.3. Log4net输出文件路径
3.4. 嵌入资源文件
3.5. 单元测试
3.6. setup工程配置
3.7. 混淆
4. Hybrid
4.1. 框架
4.2. 禁止选中文字
4.3. 引用component
4.4. 生成二维码
5. 常识
5.1. 统一信用码编码规则及校验
5.2. 行政区划编号
5.3. Git命令集
a)在app下创建目录libs
b)在app\build.grale中增加implementation fileTree(dir: 'libs', include : ['*.jar','*.aar'])
c)将jar、aar文件拷贝到下面;
d)如果AndroidStudio不能识别,则点击菜单File->Invalidate caches/Restart,然后等等重启即可;
如果手动在AndroidStudio的Device File Explore中创建路径、文件,会导致在app中无权限访问,必须在App中自己创建。
工程目录下build.gradle中指定的是AndroidStudio的gradle的版本,可能是适配器,尽量不要改,或者改成AndroidStudio的版本;
gradle\wrapper\gradle-wrapper.properties指定gradle版本,路径可以写成本地下载的zip文件,比如file\:///本地路径,所以这个目录下gradle的zip文件不可以删除。这样可以避免不同的工程都下载一遍。
这两个插件是不可以禁用的,如果禁用,AndroidStudio启动会异常。
这时可以在disabled_plugins.txt中删除相应记录即可,位置如下:
C:\Users\用户名\AppData\Roaming\Google\AndroidStudio4.1\disabled_plugins.txt
在项目build.gradle中删除导致错误的行,然后在Tools-Kotlin选择运行Config Kotlin in Project即可。
每次修改gradle文件,会导致无法编译运行工程,这时选择File->Sync Project With Gradle Files后即可。
菜单View-Tool Windows中,打开logcat查看日志。
还有其他一些功能也在此目录下;
菜单 Code-Optimize Imports可以自动删除所有多余的import;或者使用ctrl+alt+’o’热键。
在Settings-Inspections中搜索提示的关键词,找到规则,然后勾选或勾除
比如将样例工程修改成最终的工程名称,按以下步骤即可完成:
1.关闭Android Studio;
2.修改项目文件夹的名字;
3.修改OldProjectName.iml文件(在项目的根目录的.idea目录下)的名称为新项名称,即OldProjectName.iml修改为NewProjectName.iml;
4.修改.idea/workspace.xml中相应的名称;
5.修改app/build.gradle中的applicationId;
6.然后把该文件中的external.linked.project.id的值也设置为新项目的名称,即 external.linked.project.id=”NewProjectName”;
7.再次打开AndroidStudio即可。
adb install xxx.apk 如果已安装了,此时会提示
Failure [INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install xxx without first uninstalling.]
使用adb install -r xxx.apk,可以覆盖安装它,但是仍然保留前面的数据。
以下操作是在“Android Studio Flamingo | 2022.2.1 Patch 2”中执行的,其他版本可能不同。
在项目根目录的build.gradle中修改applicationId,如果需要generated的包名也跟着改变,还需要修改build.gradle中的namespace。然后在build菜单中选择“Clean project”,然后在File菜单中选择“Sync Project With Gradle files”,一次不行就执行几次。如果还不行就在File菜单中选择“Invalidate Caches”,重启后再同步几次,直到出现generated目录为止。
在模拟器内部,宿主机器IP为10.0.0.2,模拟器自身IP为10.0.2.15/127.0.0.1/localhost
如果需要在宿主机中直接访问模拟器内部的TCP端口,需要先做映射。
adb forward tcp:8081 tcp:8080
这样就可以访问 http://localhost:8081/xxxxx,请求会被转到虚拟机的8080端口
adb -s emulator-5554 shell
一般是路由器设置有问题,可能在路由器无线设置中开启了AP隔离,使得同一路由器下各个节点之间不可互通。
网络防火墙默认是不会禁用出站请求的,但是如果安装了360,在360的安全防护中心->入口防护体系中,如果选择了局域网防护,则PC无法联通手机。
首先,PC上需启动web服务;
其次,要在系统防火墙高级设置中,添加入站规则开放相应的端口,比如TCP的8080端口;
最后,如果安装了360,需要在安全防护中心->系统防护体系中,关闭网络安全防火。
插入一张Sim卡,没用的Sim卡也可以
不同型号得手机,包括华为、小米等,都是在设置的安卓版本上多次点击,即可进入开发者模式。进入开发者模式后,才可以打开USB调试。
华为手机默认日志级别是info,无论AndroidStudio中设置的是什么,如果要打开debug级别,按以下步骤设置。
1.拨号界面拨号*#*#2846579#*#*可以看到工程菜单;
2.选择后台设置进入;
3.打开 LOG设置,选择 AP日志;
4.回到AndroidStudio中,改变一下日志级别,就可以看到debug了;
5.如果还是无法显示,但是adb logcat -d可以查看,则重启以下AndroidStudio即可。
基于SwiftNio开发webserver,SwiftNio是iOS中的netty。
https://www.5axxw.com/wiki/content/zdz096https://www.5axxw.com/wiki/content/zdz096
其他的如GCDWebServer、CocoaHttpServer都已长期无更新
在包上点右键,选择Refactor,出现更名窗口,输入新的名称,一定要选择Rename subpackages,否则只会新建一个空的包
在项目的gradle文件的android下添加以下配置,将此功能关闭掉
aaptOptions{
ignoreAssetsPattern '!._'
}
下载安装:与java配置完全相同,解压后,配置JAVA_HOME以及将bin设置到系统变量path中
安装native-image:gu install native-image
安装llvm:gu install llvm-toolchain
安装js引擎:gu install js
原生编译命令:native-image 或者gradle nativeCompile
Js插件下载:
https://github.com/graalvm/graalvm-ce-builds/releases/tag/vm-22.3.2
Gradle配置见以下连接:
https://graalvm.github.io/native-build-tools/latest/gradle-plugin-quickstart.html
graalvm-ce-java11-linux-amd64-22.3.2.tar.gz
如果不用内嵌的js支持,可以不用安装js
js-installable-svm-java11-linux-amd64-22.3.2.jar
如果不作原生编译,可以不安装native-image
native-image-installable-svm-svmee-java11-windows-amd64-22.3.2.jar
插件安装命令 gu install js 或者native-image是从github下载的,所以很慢,并且经常搞到一半提示下载失败,所以找到github网站直接用迅雷下载到本地后,再用命令行从本地安装。
tar xfz graalvm-ce-java11-linux-amd64-22.3.1.tar.gz
【注意】不要解压在/root下,因为这个目录是root用户的根目录,其他用户无法访问
export JAVA_HOME=解压路径
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
gu install -L js-installable-svm-java11-linux-amd64-22.3.1.jar
不要使用gu install js,因为国内访问github不顺畅,安装极难成功,所以用下载工具(比如迅雷)下载后再在本地安装。
用root用户安装服务是个坏习惯,特别是对外保留接口的服务,一旦有漏洞,黑客获取的就是root权限,所以另建用户安装服务。
useradd -m mesh
-m参数要求系统在/home下自动创建用户目录,mesh为用户名称
passwd mesh
为用户设置一个密码
服务程序运行在8523端口,需要将80与443都转发到这个端口,用iptables添加转发规则就可以实现。
1.首先安装iptables,如果已安装,开启它就可以了;
//systemctl stop firewalld # 关闭防火墙
yum -y install iptables-services # 安装 iptables 服务
systemctl enable iptables # 设置 iptables 服务开机启动
systemctl start iptables # 启动 iptables 服务
service iptables save # 保存 iptables 配置
service iptables restart # 重启 iptables 服务
2.开放端口;
iptables服务启动后,默认禁止了1024以上的端口,所以必须打开
iptables -I INPUT -p tcp --dport 8523 -j ACCEPT
3.然后添加端口转发规则;
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8523
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8523
4.查看某个端口的转发规则
iptables -t nat -L -n | grep 80
5.删除端口转发规则
iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8523
6.最后,保存规则。
service iptables save
这样在80与443端口都可以访问。
Linux下生成图片验证码,在FontManagerFactory出现中异常,是因为没有安装字体。使用以下命令安装:
yum -y install fontconfig
fc-list查看已安装的字体
在AndroidMenifest.xml中设置,与application同一级别
同时,在application中设置android:requestLegacyExternalStorage="true"
实现一个删除数据的Activity,并在AndroidMenifest.xml-application-android:manageSpaceActivity引用此Acitivity,实现自定义的删除数据管理界面,在此只删除可以删除的,或者全部不删除,比如禁止删除sqlite数据库等。
此Activity的定义与普通Activity毫无差异。
在AndroidMenifest.xml-application-android:networkSecurityConfig中可以自定义安全策略,比如预置自签名的根证书等。
比如okhttp4.x,提示Failed resolution of: Lkotlin/jvm/internal/Intrinsics,
Kotlin并无特别的优点,建议别用了。限制OkHttp4依赖Kotlin,也用不成了。
使用KeyStore进行加解密,KeyStore的底层用的是Tee。
它的问题是,在黑屏情况下,无法使用。
EncryptedSharedPreferences 使用的也是KeyStore。
https://source.android.google.cn/security/keystore?hl=zh-cn
使用CA机构签发证书,通常成本较高,对于一个测试应用,没必要。所以自己产生一个自签名的根证书;然后用根证书产生二级证书;最后用二级证书生成自己的用户证书。这样就形成了一个证书链。在程序中预置根证书,并信任自己的根证书即可。
自签名证书链可以参照以下连接:
KeyTool生成证书链及使用_flyinmind的博客-CSDN博客
以上连接介绍了使用keytool生成根证书、二级证书、三级证书的全部过程。
使用ApplicationProvider.getApplicationContext获得Context,在这个Context中取得的路径是可以读写,写入的内容会存在正式的应用中,而不是在测试的应用中。
在测试函数前加@Before与@After注解,可以控制放在最前面与最后面执行,利用它们做准备与清理工作。
logback读配置文件时,其中用到的属性,用${propertyName}引用。属性需要在初始化的Context中设置,比如指定根路径。此Context不能reset,否则property会丢失。
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
lc.putProperty("loggerHome", outputDir);
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(lc);
//lc.reset(); //reset会清除property
configurator.doConfigure(cfgFile);
StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
在一些例子中,出现诸如DATA_DIR、PACKAGE_NAME等属性,其实它们不能用,通过看代码,猜测可能是因为logback获取应用Context的方法有误。所以需要在程序里加载配置前,设置自定义属性,然后在logback.xml中引用。
版本发布需证书进行签名,这个证书可以使用EC也可以使用RSA,可以用证书链进行签名。Debug情况下,生成了默认的证书,但是发布时不要使用。
Release时,选择菜单Build->Generate Signed Bundle/APK,选择已有的证书或新建一个证书,此证书要伴随应用终身,所以必须保存好,并且记住key密码及store密码。
也可以使用自己签名的证书,生成方法请参考以下连接:
KeyTool生成证书链及使用_flyinmind的博客-CSDN博客
在“new->image asset”中创建的图标可以保证在不同分辨率下,提供不同的图标,保障合适的清晰度。但是image asset创建的图标与app的工程是独立的,需要将它们拷贝到main的res目录下,并且,不能忘记拷贝mipmap-anydpi-v26或者mipmap-anydpi-v24与values目录,这两个目录不是打酱油的,如果不拷贝它,图标就不会更新,因为安卓里面使用的是mipmap-anydpi-vxx.xml,由它区分不同的分辨率,选择不同的图标。
虽然名称中有shared的,其实进程间共享时有诸多问题,最大的问题是不同步。
SharedPreferences第一次打开时会从配置文件中读取k-v对,存到一个map中,后面的变更使用Editor.apply,Editor.commit写到文件中。如果其他进程也在修改SharedPreferences,当前进程是不能即使感知的,除非重新调用getSharedPreferences:
Context.getSharedPreferences(NAME, Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
注意要设置MODE_MULTI_PROCESS(此标志位已不建议使用了),此标志位只是告诉getSharedPreferences在获得SharedPreferences对象时,重新读取一次文件,并不会保证多进程之间的同步;如果不设置,则直接使用以前曾经打开过的SharedPreferences对象(SharedPreferences也会缓存)。
应用安装在programs目录下时,程序是无权限写当前路径的,可以通过
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
获得应用可以写入的路径,比如C:\Users\帐号\AppData\Roaming\应用名称。在此路径下可以写入日志、运行时文件等。
代码中可以通过判断DEBUG宏是否定义给出不同的实现。
#if DEBUG
public const string API_DOMAIN = "192.168.0.102";
#else
public const string API_DOMAIN = "api" + CERT_DOMAIN;
#endif
为了使DEBUG生效,还必须右键项目,选择“属性->生成”,在DEBUG配置中,选中“定义DEBUG常数”,否则#if DEBUG判断将失败
与目录权限有关,需要根据运行时情况设置日志输出的根路径,可以设置 GlobalContext.Properties["loggerHome"] = outputDir;
然后在log4net.xml的appender.file中引用loggerHome,形式如下:
注意,一定要设type为log4net.Util.PatternString,否则%property{loggerHome}被当成普通字符串解析
推荐以文件形式嵌入资源,这样便于直接在文件夹中修改文件,而不必每次修改文件后重新刷新到Resources.resx中
在工程上右键,选择添加->新建文件夹,建立Resources目录,然后在里面添加各种文件,注意,资源的生成操作一定要选择“嵌入的资源”。
然后在程序中,使用如下方式打开资源文件流:
Assembly assm = Assembly.GetExecutingAssembly();
Stream s = assm.GetManifestResourceStream("工程名.Resources." + fileName);
此处的fileName是包括扩展名的。
首先写单元测试函数,在class上面写 [TestClass],测试函数上写[TestMethod],通过Assert.xxx断言。
然后在视图菜单中打开“测试资源管理器”,一定要选中那个烧瓶形状的图标,然后运行所有测试。单元测试做完之后,建议关闭“测试资源管理器”,它会占用一部分资源。
.net自带的打包工具很别扭,开发了这么多年也没有提升。所以,项目使用inno setup制作安装文件,其中要包括release目录下的dll。在使用webview2的情况下,需要包括runtimes\win-x64\native\WebView2Loader.dll。
如果用打包成中文,在添加ChineseSimplified.isl时,需要转为utf8-with-BOM格式(可以用notepad++修改),否则界面会显示乱码;如果还需要指定license等文件,也同样要改成utf8-with-BOM格式。
使用.Net reactor,选中release下的主程序exe,然后选中obfuscation,对程序进行混淆。混淆之后再用inno settup生成安装包。
使用vue+vue-router+quasar开发,在浏览器中输出界面,调用底层的接口。
注意:vue要使用vue.global.prod.js版本,不能使用vue.runtime.global.prod.js。
可以从https://cdn.jsdelivr.net/npm/vue@next/dist/下载。
quasar从https://quasar.dev/start/umd下载,包括quasar.umd.prod.js与quasar.prod.css,这个连接中css可以与quasar.prod.css合并,其中用到的字体也需要逐个下载,放到本地,链接为:
https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons
在游戏的场景中,经常要用到拖动,容易造成文字被选中,这时可以通过在css中增加user-select: none; 来禁止选中文字
1) 引入component文件
import AlertDialog from "/assets/v3/components/alert_dialog.js"
2) 注册component
app.component('component-alert-dialog', AlertDialog);
注册要放在app.mount之前,否则调用component中方法会提示xxx is not a function
3) 在template中引入component
4) 在js中调用component
this.$refs.errDlg.show(“xxxx”);
因为不是在nodejs中开发,不能用import方式引入qrcodejs2,所以只能在index.html直接包含它:
然后,在template中增加一个div,用以容纳二维码,这里用的是相对宽度vw,所以在生成时要计算一下。
最后,在需要显示时调用:
new QRCode(this.$refs.qrCodeUrl, {
text: 'https://www.baidu.com',
width: document.documentElement.clientWidth * 0.6,
height: document.documentElement.clientWidth * 0.6,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
如果用在dialog中,必须在dialog的@show中调用显示二维码,如果太早了,dialog的元素还没有创建,此时显示就会失败
规则:【微科普】教你看懂统一社会信用代码_机构
Java实现:校验社会统一信用代码JAVA_王魂凤气的博客-CSDN博客_校验统一社会信用代码
https://www.mca.gov.cn/article/sj/xzqh/1980/202105/20210500033655.shtml
请参照这篇文章Git操作备忘_flyinmind的博客-CSDN博客