开发至简网格的过程中,既要做服务侧开发,也要多端开发,服务侧分为JAVA服务侧、Android服务侧,端侧分为安卓、Windows,技术繁杂,碰到不少基本问题,全部记录在这里,便于以后查找。
顺便做个小广告,至简网格是一套端&云结合的开发框架,极大简化了服务侧与端侧开发,服务侧使用简单的json配置与sql、js脚本,就可以搞定95%以上的业务场景;端侧支持Android与Windows,本质是一个轻应用开发框架,用vue+quasar实现UI,使用极其简单。实现了几个业务代码,比如CRM、会员等,已在码云、CSDN开源。项目还在持续完善中,欢迎使用。
目录
1.1.6. Kotlin-android not found错误
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。并将%JAVA_HOME%\bin设置到系统变量path中
安装native-image:gu install native-image
安装llvm:gu install llvm-toolchain
安装js引擎:gu install js
原生编译命令:native-image 或者gradle nativeCompile
Js插件下载(选择正确的版本,注意下载jar格式的):
下载的版本号必须与graalvm一致,graalvm版本通过 java -version查看
graalvm-ce-java11-linux-amd64-22.3.1.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网站,直接用迅雷下载到本地后(一定要注意,下载amd的jar文件),再用命令行从本地安装。
gu install -L 本地安装文件 js
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查看已安装的字体
出来要开启USB调试开关外,禁止权限监控的选项不能关闭,否则所有需要存储、网络等的权限申请都会被禁止
在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注解,可以控制放在最前面与最后面执行,利用它们做准备与清理工作。
Java在eclipse中可以将文件放在与java同级的resources目录中,然后使用classloader加载:
InputStream in = XX.class.getClassLoader().getResourceAsStream("fileName");
Junit测试代码所需资源,就放在Junit源码对应目录下的resources目录。
但是在Android studio中不能这样用,必须用context.getAssets().open("fileName")打开输入流,而在JUnit里,重点是怎样获得context,推荐以下方法:
- Context context = ApplicationProvider.getApplicationContext();
- InputStream in = context.getAssets().open("fileName")
2.5. Logback日志
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博客