Javascript 在Android Webview内部导入ES6-不是构造函数错误

Javascript 在Android Webview内部导入ES6-不是构造函数错误,javascript,android,ecmascript-6,webview,three.js,Javascript,Android,Ecmascript 6,Webview,Three.js,我正在WebView中渲染一个html网页,它使用three.js渲染3D模型。到目前为止,所有这些都运作良好。我现在尝试添加触摸/拖动控件来移动相机。我找到了一些示例代码来实现这个功能,并且已经实现了它。以下是代码的相关部分: import * as tc from './TrackballControls.js'; //.... controls = new tc.TrackballControls( camera , renderer.domElement); controls.rotat

我正在WebView中渲染一个html网页,它使用three.js渲染3D模型。到目前为止,所有这些都运作良好。我现在尝试添加触摸/拖动控件来移动相机。我找到了一些示例代码来实现这个功能,并且已经实现了它。以下是代码的相关部分:

import * as tc from './TrackballControls.js';
//....
controls = new tc.TrackballControls( camera , renderer.domElement);
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
在Crome和Firefox的PC上,一切都很完美,我的模型渲染和拖动确实会改变相机视图。在我的Android设备上的Chrome和Firefox中,通过本地网络加载页面,一切正常

但是,在我的应用程序内的WebView中,我遇到以下错误:

Uncaught TypeError: tc.TrackballControls is not a constructor
似乎创建TrackballControls对象失败了。为什么它会在WebView中以这种方式失败,而不是在同一部手机的Chrome中

这是我的html应用程序目录结构:

我编辑了three.module.js和TrackballControls.js,以说明它们位于同一目录中,如下所示:

// in index.html js:
import * as THREE from './three.module.js';
import * as tc from './TrackballControls.js';    

// in TrackballControls.js:
import {
  EventDispatcher,
  MOUSE,
  Quaternion,
  Vector2,
  Vector3
} from "./three.module.js";
在html/javascript或Android java代码中是否有我可以修改的内容,以使其在WebView中正常工作

我在两个不同的设备上进行了尝试,它们的webview userAgent字符串为:

"Mozilla/5.0 (Linux; Android 6.0.1; S60 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/79.0.3945.93 Mobile Safari/537.36", source: https://appassets.androidplatform.net/assets/www/cpb_3d_model_wgt/index.html (27)

编辑更多信息: 我试图使用以下内容从资产目录中提供我的页面:

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
            .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
            .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this))
            .build();

    wv.setWebViewClient(new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view,
                                                          WebResourceRequest request) {
           if (!request.isForMainFrame() && request.getUrl().getPath().endsWith(".js")) {
                Log.d(TAG, " js file request need to set mime/type " + request.getUrl().getPath());
               try {
                   return new WebResourceResponse("application/javascript", null, new BufferedInputStream(view.getContext().getAssets().open("www/cpb_3d_model_wgt/three.module.js")));
               } catch (IOException e) {
                   e.printStackTrace();
               }
            }
            return assetLoader.shouldInterceptRequest(request.getUrl());
        }

        @RequiresApi(api = Build.VERSION_CODES.M)
        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            super.onReceivedError(view, request, error);
            //Log.d(TAG, "error: " + error.getDescription());
            Log.d(TAG, "error: " + request.getUrl());
        }
    });

    wv.loadUrl("https://appassets.androidplatform.net/assets/www/cpb_3d_model_wgt/index.html");
通过这种方式提供页面,我得到的是
而不是构造函数
错误。我使用chrome remote device inspector查看了TrackballControl.js文件的网络请求,我看到了以下内容:

当使用python web服务器从我的PC提供相同的页面时,一切正常(无错误,所有功能正常),以下是响应标题:

据我所知,响应或头导致导入出现问题,导致代码失败,因为导入的构造函数无法正确存在

一旦我注意到响应标题中的这种差异,我就放弃了
WebViewAssetLoader
,开始使用NanoHTTPD为我的页面提供服务,当它以这种方式提供时,一切都会按预期进行


另一个编辑:现在回顾我的资产加载器/截获请求代码,我可以看到我硬编码了“错误”的js文件,以返回每个以.js结尾的请求,这很可能是“非构造函数错误”我的错误的原因,当我最初发布问题时,我应该包含该代码,但我忽略了它。

TrackballControls.js
不是ES6模块,并且不导出
TrackballControls
构造函数<代码>轨迹球控件
连接到
三个
ts
可能只是一个空对象,
ts.TrackballControls
未定义。 定义
控件
,如下所示

controls = new THREE.TrackballControls( camera , renderer.domElement);

我的答案是基于Github上的这一点。

TrackballControls.js不是作为一个可以导入的模块编写的。相反,它假定
THREE
变量是全局可用的,并将其附加到
THREE
。要解决此问题,您可能需要将其复制并粘贴到您自己的文件中(我们称之为
TC.js
),并在开始和结束时进行一些更改:

TC.js: 现在,您应该能够在项目中使用自己的
TC.js
文件:

main.js: 我在下面举了一个例子来演示复制粘贴
TrackballControls
如何通过将其作为一个独立变量来继续工作。通过上面提到的修改,前600多行实际上是复制粘贴的。场景设置的其余部分位于JS的末尾:

//在您的代码中,您需要在这里导入三个,而不是通过标签
//从“三”中导入*作为三;
const TrackballControls=函数(对象,DOMELENT){
if(domeElement==未定义)console.warn('THREE.TrackballControls:第二个参数“domeElement”现在是必需的');
if(domElement==document)console.error('THREE.TrackballControls:“document”不应用作目标“domElement”。请改用“renderer.domElement”);
var_this=这个;
var STATE={NONE:-1,旋转:0,缩放:1,平移:2,触摸旋转:3,触摸缩放平移:4};
this.object=对象;
this.domElement=domElement;
//原料药
this.enabled=true;
this.screen={left:0,top:0,width:0,height:0};
这1.rotateSpeed=1.0;
这个.zoomSpeed=1.2;
这个速度=0.3;
this.noRotate=false;
this.noZoom=false;
this.noPan=false;
this.staticMoving=false;
该系数为0.2;
此值为0.minDistance=0;
这个.maxDistance=无穷大;
this.keys=[65/*A*/,83/*S*/,68/*D*/];
this.mouseButtons={LEFT:THREE.MOUSE.ROTATE,MIDDLE:THREE.MOUSE.ZOOM,RIGHT:THREE.MOUSE.PAN};
//内部构件
this.target=new THREE.Vector3();
var EPS=0.000001;
var lastPosition=new THREE.Vector3();
var-lastZoom=1;
var_state=state.NONE,
_keyState=STATE.NONE,
_eye=新的三个向量3(),
_movePrev=new THREE.Vector2(),
_moveCurr=new THREE.Vector2(),
_lastAxis=新的3.Vector3(),
_lastAngle=0,
_zoomStart=new THREE.Vector2(),
_zoomEnd=new THREE.Vector2(),
_TouchZoomInstanceStart=0,
_TouchZoomInstanceEnd=0,
_panStart=new THREE.Vector2(),
_panEnd=new-THREE.Vector2();
//重置
this.target0=this.target.clone();
this.position0=this.object.position.clone();
this.up0=this.object.up.clone();
this.zoom0=this.object.zoom;
//事件
var changevent={type:'change'};
var startEvent={type:'start'};
var endEvent={type:'end'};
//方法
this.handleResize=函数(){
var box=this.domeElement.getBoundingClientRect();
//调整来自jquery offset()函数中的类似代码
var d=this.domeElement.ownerDocument.documentElement;
this.screen.left=box.left+window.pageXOffset-d.clientLeft;
this.screen.top=box.top+window.pageYOffset-d.c
controls = new THREE.TrackballControls( camera , renderer.domElement);
// 1. Import THREE instead of assuming it's globally available
import * as THREE from './three.module.js';

// 2a. Remove "THREE." and make it a stand-alone variable
var TrackballControls = function ( object, domElement ) {

    // ... All 600+ lines of internal content stays the same

};

// 2a. Remove "THREE." at the bottom of the file as well
TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
TrackballControls.prototype.constructor = TrackballControls;

// 3. Export the object to be used in other files
export default TrackballControls;
import * as THREE from './three.module.js';
import TrackballControls from 'TC.js';

const controls = new TrackballControls(camera , renderer.domElement);