HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

参数错误,请通过HBuilder打开 pwd

云打包 阿里云OSS

参数错误,请通过HBuilder打开 pwd 请问有没有大佬知道如何解决?

参数错误,请通过HBuilder打开 pwd 请问有没有大佬知道如何解决?

谷歌上架提示,应用必须支持 16 KB 的内存页面大小

应用上架

如题所示,看附加图片,最后期限11月1日,如何解决该问题?

如题所示,看附加图片,最后期限11月1日,如何解决该问题?

解决微信小程序真机TextDecoder流式解析失败指南

真机调试 微信小程序 sse

以下均以经过实践:

解决微信小程序真机TextDecoder流式解析失败指南

有问题可以关注下公众号:一诺滚雪球,一起学习交流!

以下均以经过实践:

解决微信小程序真机TextDecoder流式解析失败指南

有问题可以关注下公众号:一诺滚雪球,一起学习交流!

uniapp换肤最佳实践

换肤

以下均已实际验证过:

uniapp换肤最佳实践

有问题可以关注下公众号:一诺滚雪球,一起学习交流!

以下均已实际验证过:

uniapp换肤最佳实践

有问题可以关注下公众号:一诺滚雪球,一起学习交流!

让UniApp支持React

h5 App 小程序

首先dcloud官方花费了巨大的资源保证了全端的api、开发体验保持一致、对于前端开发来说抹平了太多的平台差异,非常之牛逼!!!
uniapp的跨平台能力和生态都非常不错,尤其是在当你需要夸各种平台的时候一套完整的api是多么的珍贵,如果不考虑小程序环境的话那开发起来还是非常顺手的,但是当用uniapp开发小程序的时候,由于小程序环境的限制,太多的特性不能使用,尤其是JSX的能力,这样的话开发起来就束手束脚,很多非常平常的功能,比如说全局的Toast,Modal等等都需要以一个非常受限的方式实现!!!

假设下面这段代码可以直接运行在uniapp中那么开发起来就会无比丝滑

const Sub = (props: any) => {  
      const { children } = props  
      const [value, setValue] = useState(100)  
      useEffect(() => {  
        const timer = setInterval(() => {  
          setValue((value) => {  
            if (value >= 110) {  
              clearInterval(timer)  
            }  
            return value   1  
          })  
        }, 1000)  
        return () => {  
          clearInterval(timer)  
        }  
      }, [])  
      return (  
        <View>  
          sub  
          {value}  
          {value % 2 === 0 ? children : null}  
        </View>  
      )  
    }  
    const Hello = (props: any) => {  
      const [value, setValue] = useState(200)  
      const { unmount } = props  
      const [visible, setVisible] = useState(true)  
      useEffect(() => {  
        if (!visible) {  
          setTimeout(() => {  
            unmount()  
          }, 500)  
        }  
      }, [visible])  
      return (  
        <wd-popup  
          model-value={visible}  
          root-portal={true}  
          position="bottom"  
          onEnter={(event) => {  
            console.log('enter')  
          }}  
          onClose={() => {  
            console.log('close')  
          }}  
        >  
          <Sub a={2}>  
            <View>  
              {true}  
              {false}  
            </View>  
          </Sub>  
          {value % 2 === 0 ? <View>hello react</View> : null}  
          <View>{value}</View>  
          <Button onClick={() => setValue((v) => v   1)}>count  </Button>  
          <Button onClick={() => setValue((v) => v - 1)}>count -</Button>  
          <Button  
            onClick={(event) => {  
              console.log('remove', event)  
              setVisible(false)  
            }}  
          >  
            remove  
          </Button>  
        </wd-popup>  
      )  
    }  

    const id = renderRef.value?.render(  
      <Hello  
        unmount={() => {  
          renderRef.value?.unmount(id)  
        }}  
      />  
    )  

基于这个理由我又造了个轮子,可以让下面的代码运行在各个平台上成了现实,感兴趣的伙伴可以试用下面这个包

安装插件

# 安装插件包  
npm i @js-css/uni-app-react  
# 安装依赖包  
npm i preact @types/react

vite.config.ts 中添加如下配置

import { defineConfig } from 'vite'  
import uni from '@dcloudio/vite-plugin-uni'  
import { UniAppReact } from '@js-css/uni-app-react/dist/plugins/jsx'  
import * as path from 'node:path'  

// https://vitejs.dev/config/  
export default defineConfig({  
  plugins: [  
    // 添加插件  
    UniAppReact(),  
    uni(),  
  ],  
  resolve: {  
    alias: {  
      '@': '/src',  
      // 添加下面四个alias  
      react: path.resolve(__dirname, './node_modules/preact/compat'),  
      'react-is': path.resolve(__dirname, './node_modules/preact/compat'),  
      'react-dom': path.resolve(__dirname, './node_modules/preact/compat'),  
      '@js-css/uni-app-react': path.resolve(  
        __dirname,  
        './node_modules/@js-css/uni-app-react'  
      ),  
    },  
  },  
})

pages.json 中添加一个全局组件 "document": "/document" 该组件由插件自动注入

{  
  "pages": [  
    ...  
  ],  
  "globalStyle": {  
    "navigationBarTextStyle": "black",  
    ...  
    // 添加一个固定的全局组件,该组件由插件自动注入,只需要添加配置即可  
    "usingComponents": {  
      "document": "/document"  
    }  
  }  
}  
继续阅读 »

首先dcloud官方花费了巨大的资源保证了全端的api、开发体验保持一致、对于前端开发来说抹平了太多的平台差异,非常之牛逼!!!
uniapp的跨平台能力和生态都非常不错,尤其是在当你需要夸各种平台的时候一套完整的api是多么的珍贵,如果不考虑小程序环境的话那开发起来还是非常顺手的,但是当用uniapp开发小程序的时候,由于小程序环境的限制,太多的特性不能使用,尤其是JSX的能力,这样的话开发起来就束手束脚,很多非常平常的功能,比如说全局的Toast,Modal等等都需要以一个非常受限的方式实现!!!

假设下面这段代码可以直接运行在uniapp中那么开发起来就会无比丝滑

const Sub = (props: any) => {  
      const { children } = props  
      const [value, setValue] = useState(100)  
      useEffect(() => {  
        const timer = setInterval(() => {  
          setValue((value) => {  
            if (value >= 110) {  
              clearInterval(timer)  
            }  
            return value   1  
          })  
        }, 1000)  
        return () => {  
          clearInterval(timer)  
        }  
      }, [])  
      return (  
        <View>  
          sub  
          {value}  
          {value % 2 === 0 ? children : null}  
        </View>  
      )  
    }  
    const Hello = (props: any) => {  
      const [value, setValue] = useState(200)  
      const { unmount } = props  
      const [visible, setVisible] = useState(true)  
      useEffect(() => {  
        if (!visible) {  
          setTimeout(() => {  
            unmount()  
          }, 500)  
        }  
      }, [visible])  
      return (  
        <wd-popup  
          model-value={visible}  
          root-portal={true}  
          position="bottom"  
          onEnter={(event) => {  
            console.log('enter')  
          }}  
          onClose={() => {  
            console.log('close')  
          }}  
        >  
          <Sub a={2}>  
            <View>  
              {true}  
              {false}  
            </View>  
          </Sub>  
          {value % 2 === 0 ? <View>hello react</View> : null}  
          <View>{value}</View>  
          <Button onClick={() => setValue((v) => v   1)}>count  </Button>  
          <Button onClick={() => setValue((v) => v - 1)}>count -</Button>  
          <Button  
            onClick={(event) => {  
              console.log('remove', event)  
              setVisible(false)  
            }}  
          >  
            remove  
          </Button>  
        </wd-popup>  
      )  
    }  

    const id = renderRef.value?.render(  
      <Hello  
        unmount={() => {  
          renderRef.value?.unmount(id)  
        }}  
      />  
    )  

基于这个理由我又造了个轮子,可以让下面的代码运行在各个平台上成了现实,感兴趣的伙伴可以试用下面这个包

安装插件

# 安装插件包  
npm i @js-css/uni-app-react  
# 安装依赖包  
npm i preact @types/react

vite.config.ts 中添加如下配置

import { defineConfig } from 'vite'  
import uni from '@dcloudio/vite-plugin-uni'  
import { UniAppReact } from '@js-css/uni-app-react/dist/plugins/jsx'  
import * as path from 'node:path'  

// https://vitejs.dev/config/  
export default defineConfig({  
  plugins: [  
    // 添加插件  
    UniAppReact(),  
    uni(),  
  ],  
  resolve: {  
    alias: {  
      '@': '/src',  
      // 添加下面四个alias  
      react: path.resolve(__dirname, './node_modules/preact/compat'),  
      'react-is': path.resolve(__dirname, './node_modules/preact/compat'),  
      'react-dom': path.resolve(__dirname, './node_modules/preact/compat'),  
      '@js-css/uni-app-react': path.resolve(  
        __dirname,  
        './node_modules/@js-css/uni-app-react'  
      ),  
    },  
  },  
})

pages.json 中添加一个全局组件 "document": "/document" 该组件由插件自动注入

{  
  "pages": [  
    ...  
  ],  
  "globalStyle": {  
    "navigationBarTextStyle": "black",  
    ...  
    // 添加一个固定的全局组件,该组件由插件自动注入,只需要添加配置即可  
    "usingComponents": {  
      "document": "/document"  
    }  
  }  
}  
收起阅读 »

关于音频播放器切换多个音频播放会卡死的问题

uniapp

两套代码 自己选一套用就能解决

export class Audio {  
    constructor() {  
        this.audio = uni.createInnerAudioContext()  
        this.audio.onCanplay(() => {  
            uni.hideLoading()  
        });  
        this.audio.onTimeUpdate(() => {  
            uni.$emit('time', this.audio.currentTime)  
        });  
        this.audio.onPlay(() => {  

        });  
        this.audio.onPause(() => {});  
        this.audio.onEnded(() => {  
            this.audio.playbackRate = 1  
            uni.$emit('playend')  
        })  
    }  
    changePlaySudu(sudu) {  
        this.audio.playbackRate = sudu  
    }  
    play(url) {  
        if (this.audio.src == url) {  
            this.audio.seek(0)  
        } else {  
            this.audio.src = url  
        }  
        this.audio.play()  
    }  
    end() {  
        this.audio.pause()  
    }  
    dele() {  
        this.audio.pause();  
        this.audio.destroy();  
        this.audio = null;  
    }  
}  
export class Audios {  
    constructor() {  
        this.audio = uni.createInnerAudioContext();  
        this.audio.autoplay = true;  
        this.subscribers = {};  
        this.startSlider = 0;  
        this.endSlider = 0;  
        this.isPaused = false;  
        this.loadInitialAudio();  
    }  
    async loadInitialAudio() {  
        this.audio.onCanplay(() => {  
            if (this.startSlider) {  
                this.audio.pause();  
                this.audio.seek(this.startSlider);  
                this.audio.play();  
            }  
            this.emit('duration', this.audio.duration);  
            uni.hideLoading();  
        });  
        this.audio.onTimeUpdate(() => {  
            console.log(this.audio.currentTime);  
            this.emit('time', this.audio.currentTime, this.audio.duration);  
            if (this.endSlider > 0 && this.audio.currentTime > this.endSlider) {  
                this.audio.pause();  
            }  
        });  
        this.audio.onPlay(() => this.emit('alignPlay'));  
        this.audio.onPause(() => this.emit('playPause'));  
        this.audio.onEnded(() => this.emit('playend'));  
    }  
    // 切换音频 重新播放  
    playAudio(audioSrc, play = true, start, end) {  
        this.audio.pause();  
        if (this.audio.src === audioSrc && !this.isPaused) {  
            this.audio.play();  
            return;  
        }  
        if (this.audio.src === audioSrc && this.isPaused) {  
            this.audio.pause();  
            this.audio.seek(0);  
            this.audio.play();  
            return;  
        }  
        this.audio.src = audioSrc;  
    }  
    //切换播放时间点  
    changeAudioPlayCurrentTime(time) {  
        this.audio.pause();  
        this.audio.seek(time);  
        this.audio.play();  
    }  
    //暂停  
    pause() {  
        this.audio.pause();  
    }  
    //继续播放  
    play() {  
        if (this.audio.src && !this.isPaused) {  
            this.audio.play();  
            return;  
        }  
    }  
    //静音  
    toggleMute() {  
        this.audio.volume = this.audio.volume == 0 ? 1 : 0;  
    }  
    //播放速度  
    changePlaybackRate(value) {  
        if (this.audio) this.audio.playbackRate = value;  
    }  
    on(event, callback) {  
        if (!this.subscribers[event]) {  
            this.subscribers[event] = [];  
        }  
        this.subscribers[event].push(callback);  
    }  
    emit(event, ...args) {  
        if (this.subscribers[event]) {  
            this.subscribers[event].forEach((callback) => callback(...args));  
        }  
    }  
    onDestroy() {  
        this.audio.pause();  
        this.audio.offEnded();  
        this.audio.offPlay();  
        this.audio.offPause();  
        this.audio.offCanplay();  
        this.audio.offTimeUpdate();  
        this.audio.destroy();  
        this.audio = null;  
        this.subscribers = {};  
    }  
}
继续阅读 »

两套代码 自己选一套用就能解决

export class Audio {  
    constructor() {  
        this.audio = uni.createInnerAudioContext()  
        this.audio.onCanplay(() => {  
            uni.hideLoading()  
        });  
        this.audio.onTimeUpdate(() => {  
            uni.$emit('time', this.audio.currentTime)  
        });  
        this.audio.onPlay(() => {  

        });  
        this.audio.onPause(() => {});  
        this.audio.onEnded(() => {  
            this.audio.playbackRate = 1  
            uni.$emit('playend')  
        })  
    }  
    changePlaySudu(sudu) {  
        this.audio.playbackRate = sudu  
    }  
    play(url) {  
        if (this.audio.src == url) {  
            this.audio.seek(0)  
        } else {  
            this.audio.src = url  
        }  
        this.audio.play()  
    }  
    end() {  
        this.audio.pause()  
    }  
    dele() {  
        this.audio.pause();  
        this.audio.destroy();  
        this.audio = null;  
    }  
}  
export class Audios {  
    constructor() {  
        this.audio = uni.createInnerAudioContext();  
        this.audio.autoplay = true;  
        this.subscribers = {};  
        this.startSlider = 0;  
        this.endSlider = 0;  
        this.isPaused = false;  
        this.loadInitialAudio();  
    }  
    async loadInitialAudio() {  
        this.audio.onCanplay(() => {  
            if (this.startSlider) {  
                this.audio.pause();  
                this.audio.seek(this.startSlider);  
                this.audio.play();  
            }  
            this.emit('duration', this.audio.duration);  
            uni.hideLoading();  
        });  
        this.audio.onTimeUpdate(() => {  
            console.log(this.audio.currentTime);  
            this.emit('time', this.audio.currentTime, this.audio.duration);  
            if (this.endSlider > 0 && this.audio.currentTime > this.endSlider) {  
                this.audio.pause();  
            }  
        });  
        this.audio.onPlay(() => this.emit('alignPlay'));  
        this.audio.onPause(() => this.emit('playPause'));  
        this.audio.onEnded(() => this.emit('playend'));  
    }  
    // 切换音频 重新播放  
    playAudio(audioSrc, play = true, start, end) {  
        this.audio.pause();  
        if (this.audio.src === audioSrc && !this.isPaused) {  
            this.audio.play();  
            return;  
        }  
        if (this.audio.src === audioSrc && this.isPaused) {  
            this.audio.pause();  
            this.audio.seek(0);  
            this.audio.play();  
            return;  
        }  
        this.audio.src = audioSrc;  
    }  
    //切换播放时间点  
    changeAudioPlayCurrentTime(time) {  
        this.audio.pause();  
        this.audio.seek(time);  
        this.audio.play();  
    }  
    //暂停  
    pause() {  
        this.audio.pause();  
    }  
    //继续播放  
    play() {  
        if (this.audio.src && !this.isPaused) {  
            this.audio.play();  
            return;  
        }  
    }  
    //静音  
    toggleMute() {  
        this.audio.volume = this.audio.volume == 0 ? 1 : 0;  
    }  
    //播放速度  
    changePlaybackRate(value) {  
        if (this.audio) this.audio.playbackRate = value;  
    }  
    on(event, callback) {  
        if (!this.subscribers[event]) {  
            this.subscribers[event] = [];  
        }  
        this.subscribers[event].push(callback);  
    }  
    emit(event, ...args) {  
        if (this.subscribers[event]) {  
            this.subscribers[event].forEach((callback) => callback(...args));  
        }  
    }  
    onDestroy() {  
        this.audio.pause();  
        this.audio.offEnded();  
        this.audio.offPlay();  
        this.audio.offPause();  
        this.audio.offCanplay();  
        this.audio.offTimeUpdate();  
        this.audio.destroy();  
        this.audio = null;  
        this.subscribers = {};  
    }  
}
收起阅读 »

ios上架app store,6.9寸、6.5寸和ipad截图的生成方法

截屏

截止到目前最新的app store上架流程中,需要上传6.9寸、6.5寸和ipad的截图,而且这个步骤是必填的。如下图:

但是我们用uniapp开发,假如使用windows开发是没有ios设备的模拟器的,而且我们也不可能因上架appstore去买这么多种ios设备来截屏, 以为只有上架的时候才需要用到这个截屏,开发的时候是不需要的,购买真机来截屏成本太高。

除了模拟器和真机测试外,还可以借助香蕉云编的合成截屏工具来合成截屏,这样就无需mac电脑,也无需购买真机,截屏工具的地址:

https://www.yunedit.com/jietu

截屏的原理比较简单,只需要上传一样相似比例的图片,它可以帮你合成一张包含ios带电池栏和底部横条栏的截图,而且符合ios的截屏尺寸。

继续阅读 »

截止到目前最新的app store上架流程中,需要上传6.9寸、6.5寸和ipad的截图,而且这个步骤是必填的。如下图:

但是我们用uniapp开发,假如使用windows开发是没有ios设备的模拟器的,而且我们也不可能因上架appstore去买这么多种ios设备来截屏, 以为只有上架的时候才需要用到这个截屏,开发的时候是不需要的,购买真机来截屏成本太高。

除了模拟器和真机测试外,还可以借助香蕉云编的合成截屏工具来合成截屏,这样就无需mac电脑,也无需购买真机,截屏工具的地址:

https://www.yunedit.com/jietu

截屏的原理比较简单,只需要上传一样相似比例的图片,它可以帮你合成一张包含ios带电池栏和底部横条栏的截图,而且符合ios的截屏尺寸。

收起阅读 »

【解决】运行到Android,找不到设备

真机运行 真机调试 Android

管理员打开cmd,运行以下命令

adb kill-server && adb start-server

管理员打开cmd,运行以下命令

adb kill-server && adb start-server