uniapp中使用cesium的各种问题
一:uniapp中是否可以使用Cesium?
先说结论:
可以,但会存在各种各样的问题和bug ,如果直接是H5没什么大的问题,主要是app,无论是引入还是打包真机模拟都有问题
二:问题的本质和原因
web端如何引入cesium就不说了,单说app端为什么不能直接引入cesium
1.静态引入,也就是在html页面中link标签引入css,script引入cesium的js文件,但是app不依赖html,无论是在本地还是读取线上服务器都不行
2.npm i的方式引入,很抱歉更不行,都知道app不是浏览器是没有window对象的,自然没有浏览器的dom对象
看官网的说法吧

三:解决方案
那我们要如何引入cesium呢 ,上面说了要使用renderjs来操作,那我们的思路就是在renderjs中动态创建script标签引入cesium的js文件
什么是renderjs 点击访问renderjs地址

四:代码实现
<template>
<view class="content">
<!-- #ifdef APP-PLUS || H5 -->
<view id="container"></view>
<!-- #endif -->
<!-- #ifndef APP-PLUS || H5 -->
<view>非 APP、H5 环境不支持</view>
<!-- #endif -->
<button @click="back"> 按钮</button>
</view>
</template>
<script module="Cesium" lang="renderjs">
export default {
data() {
return {
domlist: null, // 动态引入dom标签合集
viewer: null, // 三维视窗
}
},
mounted() {
this.initResources()
},
methods: {
// 初始化资源,加载后例化cesium
initResources() {
if (this.domlist) {
this.removeResource()
} else {
// 动态引入css文件
const linkDom = document.createElement('link')
linkDom.rel = "stylesheet"
linkDom.href = "https://cesium.com/downloads/cesiumjs/releases/1.84/Build/Cesium/Widgets/widgets.css"
document.head.appendChild(linkDom)
var cesiumS = this.requireResources('script',
'https://cesium.com/downloads/cesiumjs/releases/1.84/Build/Cesium/Cesium.js', this.initCesium)
this.domlist = [linkDom, cesiumS]
}
},
// 动态创建script引用第三方类库
requireResources(dom, src, callback) {
// 动态引入较大类库避免影响页面展示
const script = document.createElement(dom)
// view 层的页面运行在 www 根目录,其相对路径相对于 www 计算
script.src = src;
document.head.appendChild(script);
callback && (callback instanceof Function) && (script.onload = callback.bind(this));
return script
},
// 移除动态添加的标签,避免重复添加标签
removeResource() {
if (this.domlist)
for (let i = 0; i < this.domlist.length; i++) {
document.head.removeChild(this.domlist[i])
}
},
// 初始化
initCesium() {
let Cesium = globalThis.Cesium
let key =
"";
Cesium.Ion.defaultAccessToken = key;
this.viewer = new Cesium.Viewer('container', {
terrainProvider: Cesium.createWorldTerrain(), // 创建世界地形
geocoder: false, //右上角 搜索
homeButton: false, //右上角 Home
sceneModePicker: false, //右上角 2D/3D切换
baseLayerPicker: false, //右上角 地形
navigationHelpButton: false, //右上角 Help
animation: false, // 左下角 圆盘动画控件
timeline: false, //时间轴
fullscreenButton: false, //右下角 全屏控件
vrButton: false, // 如果设置为true,将创建VRButton小部件。
scene3DOnly: true // 每个几何实例仅以3D渲染以节省GPU内存
// infoBox: false //隐藏点击要素后的提示信息
})
this.viewer._cesiumWidget._creditContainer.style.display = 'none'; //隐藏版本信息
this.viewer.scene.debugShowFramesPerSecond = true; // 显示帧数
},
},
beforeDestroy() {
this.removeResource()
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#container {
width: 100%;
height: 500px;
/* background: #0ff; */
}
</style>
五:遇到的问题,各种离奇Bug
浏览器可以,但是真机模拟或者打包后报错或者白屏
第一种:Failed to execute 'texImage2D' on 'WebGL2RenderingContext': The image element contains cross-origin data, and may not be loaded.
这个意思就是uniapp访问cesium的时候跨域了,有人也给了方法就是修改源码,加一句跨域,也有人巴拉巴拉说了一堆没屁用的话
r.crossOrigin = “anonymous”。

但是你会发现,你的cesium.js中这方法是被注释掉了,没地方添加,直接说如何解决,本质是你的cesium版本太高,需要降低cesium版本最好是低于1.96版本,测试使用1.84版本即可
第二种:白屏问题Bug
三种可能性引起的
- 打包体积超过40M,cesium包体积太大导致无法加载
- 云打包别快速打包,直接用传统打包(重点)
- 引入本地的cesium的js文件路径不对,也会导致白屏,我也没搞懂这个本地引入路径要怎么整,别人那种引入不生效,搞懂了哥们踢我一下

六:剩余的坑
到这里,你的app终于是可以出现球了,但是三维gis老生常谈的问题又来了,性能问题,手机会不会变成暖宝宝,
答案是显然的,而且好多api使用不了,你需要不停的修改源码,但是基础的加载各种数据和点击事件没问题(找了一个专门做uniapp移动端cesium的同学咨询了一下,ps:他们企业都快倒闭了,感谢小伙伴的解惑,预祝下一份工作能发大财)
七:建议
其实移动端要想使用cesium有更好的方案:
1.原生安卓套壳,里面嵌套h5,使用h5实现cesium的各种功能,有大佬已经实现了,感觉才是正途
2.在uniapp中使用web-view嵌套h5,也是可以的,反正真机模拟是可以出现地球并操作的,但是打包没体验过
更多推荐
所有评论(0)