0%

自定义基座

下载源码

先去下载自定义基座的基础代码文件相关地址

使用其中的HBuilder-Integrate-AS文件包

增加自定义配置

  1. ~\HBuilder-Integrate-AS\simpleDemo\build.gradle增加如下的相关配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.core:core:1.1.0'
implementation "androidx.fragment:fragment:1.1.0"
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.facebook.fresco:fresco:2.5.0'
implementation "com.facebook.fresco:animated-gif:2.5.0"
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'androidx.webkit:webkit:1.5.0'
implementation 'com.tencent.mm.opensdk:wechat-sdk-android:+'

// 自定义基座配置
implementation "com.alibaba:fastjson:1.2.83"
implementation "com.squareup.okhttp3:okhttp:3.12.12"
implementation("net.lingala.zip4j:zip4j:2.11.5")
implementation 'com.squareup.okio:okio:1.15.0'

debugImplementation fileTree(includes: ['.jar', '.aar'], dir: 'debug/libs')
}
  1. Androidmanifest.xml的application元素增加dcloud的appkey,这个要去网站申请,并且和证书匹配。
1
2
3
<meta-data
android:name="dcloud_appkey"
android:value="填写你的appkey" />
  1. (可选)接入微信功能,同上位置,加入以下代码
1
2
3
4
5
6
7
8
9
10
11
12
<meta-data android:value="填写你的APPID" android:name="WX_APPID"/>
<activity android:name="这里填写WXEntryActivity在项目中的路径"
android:label="@string/app_name"
android:exported="true"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="填写你的APPID"/>
</intent-filter>
</activity>

我是在\src\main\java\cn.com.wxapi创建的WXEntryActivity文件,内容如下

1
2
3
4
5
6
7
8
9
10
11
package cn.com.wxapi; // 确保这行代码的包名和您的文件路径一致

import io.dcloud.feature.oauth.weixin.AbsWXCallbackActivity;

public class WXEntryActivity extends AbsWXCallbackActivity {

// 这里是空的,不需要写任何代码。
// 所有微信的回调逻辑都由它的父类 AbsWXCallbackActivity 自动处理了。
// 这个父类会负责接收微信返回的结果,并将其传递给 uni-app 的前端JS。

}
  1. 导入data文件,位置在SDK/assets/data/,导入到项目的main/assets/data/中,修改dcloud_control.xml中的appid

运行安卓直接把hbuild生成的代码移动到项目的main/assets/apps/中

一些代码问题

流式传输

流式需要使用fetch-event-source自定义,通过renderjs + fetch实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
h5PostStream(url, data) {
let controller = null;
let onChunkCallback = null;
let onErrorCallback = null;
let onCompleteCallback = null;

const streamTask = {
// 设置数据块接收回调
onChunkReceived(callback) {
onChunkCallback = callback;
},

// 设置错误回调
onError(callback) {
onErrorCallback = callback;
},

// 设置完成回调
onComplete(callback) {
onCompleteCallback = callback;
},

// 中止请求
abort() {
if (controller) {
controller.abort();
}
},
};

// 启动 SSE 连接
setTimeout(() => {
controller = new AbortController();

fetchEventSource(baseurl + url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: getToken(),
Accept: 'text/event-stream',
},
body: JSON.stringify(data),
signal: controller.signal,

// 当连接打开时
onopen(response) {
if (response.ok) {
console.log('SSE 连接已建立');
return;
}

// 处理错误状态码
if (response.status === 401 || response.status === 403) {
throw new Error('认证失败');
}

throw new Error('连接失败: ' + response.status);
},

// 当收到消息时
onmessage(event) {
if (onChunkCallback && event.data) {
// 将字符串转换为 ArrayBuffer (模拟 uni.request 的返回格式)
const encoder = new TextEncoder();
const arrayBuffer = encoder.encode(event.data).buffer;

onChunkCallback({
data: arrayBuffer,
});
}
},

// 当发生错误时
onerror(err) {
console.error('SSE 错误:', err);

// 检查是否是认证错误
if (err.message && err.message.includes('认证失败')) {
useDialog('登录过期,请前往登录', { title: '提示', showCancelButton: true })
.then(() => {
uni.navigateTo({
url: '/pages/login/phone/index',
});
})
.catch(err => {});
}

if (onErrorCallback) {
onErrorCallback(err);
}

// 抛出错误以停止重连
throw err;
},

// 当连接关闭时
onclose() {
console.log('SSE 连接已关闭');
if (onCompleteCallback) {
onCompleteCallback();
}
},

// 不自动重连
openWhenHidden: false,
});
}, 0);

return streamTask;
},

echarts不同于小程序写法

写于前方:如果遇到任何异常,先尝试重启,包括但不限于:重启开发者工具、重新run dev、删除dist并重新dev、重启电脑

写于前方:如果遇到任何异常,先尝试重启,包括但不限于:重启开发者工具、重新run dev、删除dist并重新dev、重启电脑

写于前方:如果遇到任何异常,先尝试重启,包括但不限于:重启开发者工具、重新run dev、删除dist并重新dev、重启电脑

更新于 2026/04/14

SSE格式异常、保存的文件无法打开、关于自动滚动、console 不显示、滚动视图、流式传输、输入框上移

阅读全文 »

需求

在开发tg miniapp的时候,有一个场景如下:

1
2
1.点击播放声音
2.连续点击,需要重复地从头再次播放。(比如声音是‘噔-噔-咚’,快速连续点击就响起‘噔-噔-噔’)

代码实现

这边给元素绑定了点击事件,当用户触发点击事件,就将音频的当前进度设置为0,并且播放。

1
2
audio.currentTime=0;
audio.play();

适配情况

这个代码在pc的chrome和android的浏览器中都可以正常实现需求。

但是ios中,会出现声音的延迟(比如声音是‘噔-噔-咚’,快速连续点击就响起‘——噔-噔-咚’,稍慢连续点击就响起‘–噔–噔–噔’)

解决方案

调用howler库

相关源码如下(源于howler库)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Call this method on touch start to create and play a buffer,
// then check if the audio actually played to determine if
// audio has now been unlocked on iOS, Android, etc.
var unlock = function(e) {
// Create a pool of unlocked HTML5 Audio objects that can
// be used for playing sounds without user interaction. HTML5
// Audio objects must be individually unlocked, as opposed
// to the WebAudio API which only needs a single activation.
// This must occur before WebAudio setup or the source.onended
// event will not fire.
while (self._html5AudioPool.length < self.html5PoolSize) {
try {
var audioNode = new Audio();

// Mark this Audio object as unlocked to ensure it can get returned
// to the unlocked pool when released.
audioNode._unlocked = true;

// Add the audio node to the pool.
self._releaseHtml5Audio(audioNode);
} catch (e) {
self.noAudio = true;
break;
}
}

// Loop through any assigned audio nodes and unlock them.
for (var i=0; i<self._howls.length; i++) {
if (!self._howls[i]._webAudio) {
// Get all of the sounds in this Howl group.
var ids = self._howls[i]._getSoundIds();

// Loop through all sounds and unlock the audio nodes.
for (var j=0; j<ids.length; j++) {
var sound = self._howls[i]._soundById(ids[j]);

if (sound && sound._node && !sound._node._unlocked) {
sound._node._unlocked = true;
sound._node.load();
}
}
}
}

// Fix Android can not play in suspend state.
self._autoResume();

// Create an empty buffer.
var source = self.ctx.createBufferSource();
source.buffer = self._scratchBuffer;
source.connect(self.ctx.destination);

// Play the empty buffer.
if (typeof source.start === 'undefined') {
source.noteOn(0);
} else {
source.start(0);
}

// Calling resume() on a stack initiated by user gesture is what actually unlocks the audio on Android Chrome >= 55.
if (typeof self.ctx.resume === 'function') {
self.ctx.resume();
}

// Setup a timeout to check that we are unlocked on the next event loop.
source.onended = function() {
source.disconnect(0);

// Update the unlocked state and prevent this check from happening again.
self._audioUnlocked = true;

// Remove the touch start listener.
document.removeEventListener('touchstart', unlock, true);
document.removeEventListener('touchend', unlock, true);
document.removeEventListener('click', unlock, true);
document.removeEventListener('keydown', unlock, true);

// Let all sounds know that audio has been unlocked.
for (var i=0; i<self._howls.length; i++) {
self._howls[i]._emit('unlock');
}
};
};

前言

tg应用开发分为机器人和小程序两部分

tg-bot

首先要在telegram的BotFather申请创建机器人,直接输入/newbot按照命令一步一步来就可以了。

成功后你会获得一串HTTP API,这个要保存下来。后续编程开发需要使用。

tgbot程序编写

bot部分参考了这位的博客

技术栈:grammY+node直接启动。以下是具体代码。

阅读全文 »

搭建个人博客的初衷,是为了不再受制于博客平台(cs*n),同时还要能专注于博客的编写而不用费心思去处理编译部署打包。(要抄配置直接拉到文章底部,我把配置文件放那了)

这里使用的是hexo博客框架next主题,用到的依赖如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"hexo": "^7.3.0",
"hexo-deployer-git": "^4.0.0",
"hexo-generator-archive": "^2.0.0",
"hexo-generator-category": "^2.0.0",
"hexo-generator-index": "^4.0.0",
"hexo-generator-search": "^2.4.3",
"hexo-generator-seo-friendly-sitemap": "^0.2.1",
"hexo-generator-tag": "^2.0.0",
"hexo-reading-time": "^1.0.3",
"hexo-renderer-ejs": "^2.0.0",
"hexo-renderer-marked": "^6.3.0",
"hexo-renderer-stylus": "^3.0.1",
"hexo-server": "^3.0.0",
"hexo-theme-landscape": "^1.0.0",
"hexo-theme-next": "^8.21.0",
"hexo-word-counter": "^0.2.0"
阅读全文 »

文中有部分名词可能不准确,见谅

本文主要介绍storybook+shadcn/ui+tailwindcss的storybook代码编写。

阅读全文 »

ps:有个需求是要等待确认交易。写这篇之后,我发现直接用回调函数要等好久好久好久。找到解决方案在这个链接但是有点麻烦。我已经弃用web3,直接使用ethersjs配合infura了,贼快。

本文将介绍如何使用web3js在Sepolia测试网完成一次交易,本文采用两种方式获得钱包,第一种是使用metamask,第二种使用web3创建。(可跳过第一节直接从第二节阅读)
使用的lib版本如下
“web-vitals”: “^2.1.4”,
“web3”: “^4.11.1”

阅读全文 »