android项目嵌套uniapp页面及交互

Posted 我靠_叫我大当家的

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android项目嵌套uniapp页面及交互相关的知识,希望对你有一定的参考价值。

之前说过会更新一期,原生android代码里怎么嵌套uniapp页面,以及两者之间怎么交互数据。今天它来了~

如果是早期的android开发工程师,一定记得当初android+webview+h5混合开发的那个阶段,这次也是类似,废话不多说,上代码,简单明了。

准备工作:

自行准备好androidstudio及安卓项目,hbuilder及uniapp项目

1. 把uniapp项目打包成后h5

对着uniapp项目,鼠标右键 -> 发行 -> 网站PC Web或者手机H5 

然后点击发行

 

经过短暂的 “真男人就5秒” 之后,控制台会打印出生成的h5工程位置

 点击就可以看到在磁盘中的位置以及内容

 

 2. 把打包的h5工程,放到android项目的assets目录下

如图所示,放在放到assets目录下,因为我是做了三个部分,转诊(referral),远程会诊(remote), 交流学习(study) 三个模块(名字是我自己自由命名的),所以只需要按上面的步骤生成三个h5工程就行。你们应该就一个,而且外层的名字可以自己命名。

 如果你发现你的android工程的目录结构跟我不一样,看一下上图,我设置箭头的位置,选择project视图模式就行了。如果你的main文件夹下没有asset目录,不会创建的话,就对着main文件夹,鼠标右键选择 New -> Folder -> Assets Folder 就可以了

 

3. 在需要嵌入uniapp页面的android页面里,使用webview并嵌套

android页面代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

android嵌套代码

private void initView() 
        //要嵌套的uniapp页面所在安卓下的路径(也就是assets下的路径,记得
        //assets路径就是要写成android_asset,不要改)
        String url = "file:///android_asset/remote/index.html";
        WebSettings webSettings = webView.getSettings();
        //可以访问https
        webSettings.setBlockNetworkImage(false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        
        //开启javascript
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDomStorageEnabled(true);
        //下面这些都是设置,自行结合项目需要删减    
        //设置可以访问文件
        webSettings.setAllowFileAccess(true);
        webSettings.setLoadsImagesAutomatically(true);
        webView.setVerticalScrollBarEnabled(false);
        webView.setHorizontalScrollBarEnabled(false);
        webSettings.setAppCacheEnabled(true);
        webSettings.setDatabaseEnabled(true);
        String dir = getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
        webSettings.setGeolocationDatabasePath(dir);
        webSettings.supportMultipleWindows();
        webSettings.setAllowContentAccess(true);
        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webView.getSettings().setDomStorageEnabled(true);
        //这一行代码很重要,先往下看,这个就是调用传值的方法,后面会解释
        //webView.addJavascriptInterface(WebUtil.getInstance(),"webUtil");
        //加载url
        webView.loadUrl(url);
        webView.setWebViewClient(new WebViewClient()
            @Override
            @SuppressWarnings("deprecation")
            public boolean shouldOverrideUrlLoading(WebView view, String url) 
                view.loadUrl(url);
                return true;
            

            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) 
                handler.proceed();// 接受所有网站的证书
                super.onReceivedSslError(view, handler, error);
            
        );
    

至此为止,你的android项目就可以成功加载uniapp打包后的页面了。但是我们肯定不只是加载个页面这么简单,还要交互数据,传值。接着往下看

1. 创建工具类,把传值操作方法放进去

public class WebUtil 

    private static WebUtil instance=new WebUtil();

    public static WebUtil getInstance()
        if(instance == null)
            instance = new WebUtil();
        
        return instance;
    

    private Context context;

    public void setContext(Context context) 
        this.context = context;
    

    @JavascriptInterface
    public String getRole()
        Integer identity = (Integer) SPUtils.getData(context, "identity", -1);
        return String.valueOf(identity);
    

    @JavascriptInterface
    public String getUserToken() 
        String token = (String) SPUtils.getData(context, "token", "");
        return token;
    

    @JavascriptInterface
    public void joinMeet(String data)
        Gson gson=new Gson();
        TodayConsultationBean bean = gson.fromJson(data, TodayConsultationBean.class);
        enterMeeting(bean);
    


    @JavascriptInterface
    public void toLogin()
        Intent intent=new Intent(context, LoginActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    

    @JavascriptInterface
    public void toBook()
        Intent intent=new Intent(context, RemoteConsultBookActivity.class);
        context.startActivity(intent);
    

    @JavascriptInterface
    public void toTrain(String meetId,String topic,String ownerName)
        Intent intent=new Intent(context, TrainVideoActivity.class);
        intent.putExtra("meetID",Integer.parseInt(meetId));
        intent.putExtra("topic",topic);
        intent.putExtra("ownerName",ownerName);
        intent.putExtra("meetPwd","");
        context.startActivity(intent);
    

    private void enterMeeting(TodayConsultationBean bean) 
        int meetID = -1;
        try 
            meetID = TextUtils.isEmpty(bean.getConference_number())?0:Integer.parseInt(bean.getConference_number());
         catch (Exception e) 
        
        if (!TextUtils.isEmpty(bean.getConference_number()))
            if (meetID < 0 || bean.getConference_number().length() != 8) 
                Toast.makeText(context, R.string.err_meetid_prompt, Toast.LENGTH_SHORT).show();
                return;
            
        
        boolean isCreateMeeting=false;
        if (bean.getIsCreateUser()==0 && TextUtils.isEmpty(bean.getConference_number()))
            isCreateMeeting=true;
        
        enterMeetingActivity(meetID, "", isCreateMeeting,bean);
    

    private void enterMeetingActivity(int meetID, String meetPswd,
                                      boolean createMeeting,TodayConsultationBean bean) 
        Intent intent = new Intent(context, MeetingsActivity.class);
        intent.putExtra("meetID",meetID);
        intent.putExtra("meetPwd",meetPswd);
        intent.putExtra("createMeeting",createMeeting);
        intent.putExtra("bean",bean);
        context.startActivity(intent);
    

可以看到,这里我就用到的一些方法。我来说明下什么意思哈

如果你希望你的这个方法能够被uniapp调用,那么就在这个方法上面加上一个注解@JavascriptInterface 即可,就标记这个方法可以被网页调用了

如果你想uniapp给android传值,你就可以在这个方法里加上入参就行,比如我这里的joinMeet方法和toTrain方法,方法的参数就是uniapp传值给android

如果你想android传值给uniapp,你就给这个方法加上返回值,如我这里的getRole和getUserToken方法

2. 把工具类对象放入到webview中(就是上面代码我注释的地方)

 这个就是把我们的工具类放入到webview中,供uniapp调用,第一个参数是工具类对象,第二个字符串参数就是给这个对象起的名字,自由命名,我起的名字叫webUtil

3. 在uniapp端调用

比如像token啊,role啊,你希望在uniapp页面一加载就要获取到,所以在工程下的App.vue里写上如下代码

<script>
	export default 
		globalData:
			token:null,
			role:-1
		,
		onLaunch: function() 
			let token=window.webUtil.getUserToken();
			let role=window.webUtil.getRole();
		    uni.setStorageSync('token',token);
			uni.setStorageSync('role',role);
			console.log('App Launch')
		,
		onShow: function() 
			console.log('App Show')
		,
		onHide: function() 
			console.log('App Hide')
		
	
</script>

就可以拿到了token和role了,放到缓存里就可以各个页面自由调用了

又或者其他页面的methods中调用

 但是注意,必须使用   window.你起的工具类对象名.方法  这样的格式来操作

好了,到此为止,android原生工程里嵌套uniapp页面,并且互相传值就搞定了

本人个人原创,如有雷同,纯属巧合,或者与本人联系,做改动。请转载或者CV组合标明出处,谢谢!(如有疑问或错误欢迎指出,本人QQ:752231513)

uni-app教程四UniAPP 路由配置及页面跳转

四、UniAPP 路由配置及页面跳转

(1) 路由配置

uni-app页面路由为框架统一管理,开发者需要在pages.json里配置每个路由页面的路径及页面样式。类似小程序在 app.json 中配置页面路由一样。所以 uni-app 的路由用法与 Vue Router 不同,如仍希望采用 Vue Router 方式管理路由,可在插件市场搜索 Vue-Router

	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
		
			"path": "pages/index/index",
			"style": 
				"navigationBarTitleText": "路由配置",
				"navigationBarBackgroundColor": "#FFFFFF",
				"navigationBarTextStyle": "black",
				"backgroundColor": "#FFFFFF",
				"enablePullDownRefresh": true
			
		,
		
			"path": "pages/list/list",
			"style": 
				"navigationBarTitleText": "路由配置2",
				"navigationBarBackgroundColor": "#FFFFFF",
				"navigationBarTextStyle": "black",
				"backgroundColor": "#FFFFFF",
				"enablePullDownRefresh": true
			
		
	],

(2) 路由跳转

uni-app 有两种页面路由跳转方式:使用 navigator组件跳转(标签式导航)、调用 API跳转(编程式导航)
框架以栈的形式管理当前所有页面,当发生路由切换的时候,页面栈的表现如下:

页面栈

框架以栈的形式管理当前所有页面, 当发生路由切换的时候,页面栈的表现如下:

路由方式页面栈表现触发时机
初始化新页面入栈uni-app 打开的第一个页面
打开新页面新页面入栈调用 API uni.navigateTo 、使用组件
页面重定向当前页面出栈,新页面入栈调用 API uni.redirectTo 、使用组件
页面返回页面不断出栈,直到目标返回页调用 API uni.navigateBack 、使用组件 、用户按左上角返回按钮、安卓用户点击物理back按键
Tab 切换页面全部出栈,只留下新的 Tab 页面调用 API uni.switchTab 、使用组件 、用户切换 Tab
重加载页面全部出栈,只留下新的页面调用 API uni.reLaunch 、使用组件

(3)获取当前页面栈

getCurrentPages0函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个
元素为当前页面,
注意:getCurrentPages 仅用于展示页面栈的情况,请勿修改页面栈,以免造成页面状态错误。

(4)路由传参与接收

说明:页面生命周期的 onLoad()监听页面加载,其参数为上个页面传递的数据,如

//在起始页面跳转到test.vue页面并传递参数
uni.navigateTo(
	url: 'test?id=1&name=uniapp'
);

url为将要跳转的页面路径,路径后可以带参数。参数与路径之间使用 ?分隔,参数键与参数值用 = 相连,不同参数用 & 分隔。如 'path?key1=value1&key2=value2' ,path为下一个页面的路径。下一个页面的onLoad函数可得
到传递的参数。

// 在test.vue页面接受参数
export default 
	onLoad: function (option)  //option为object类型,会序列化上个页面传递的参数
		console.log(option.id); //打印出上个页面传递的参数。
		console.log(option.name); //打印出上个页面传递的参数。
	

起始页面跳转到test.vue页面,并监听test.vue发送过来的事件数据

// 在起始页面跳转到test.vue页面,并监听test.vue发送过来的事件数据
uni.navigateTo(
  url: 'pages/test?id=1',
  events: 
    // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
    acceptDataFromOpenedPage: function(data) 
      console.log(data)
    ,
    someEvent: function(data) 
      console.log(data)
    
    ...
  ,
  success: function(res) 
    // 通过eventChannel向被打开页面传送数据
    res.eventChannel.emit('acceptDataFromOpenerPage',  data: 'data from starter page' )
  
)

// 在test.vue页面,向起始页通过事件传递数据
onLoad: function(option) 
  const eventChannel = this.getOpenerEventChannel();
  eventChannel.emit('acceptDataFromOpenedPage', data: 'data from test page');
  eventChannel.emit('someEvent', data: 'data from test page for someEvent');
  // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
  eventChannel.on('acceptDataFromOpenerPage', function(data) 
    console.log(data)
  )

url有长度限制,太长的字符串会传递失败,可改用窗体通信全局变量,另外参数中出现空格等特殊字符时需要对参数进行编码,如下为使用encodeURIComponent对参数进行编码的示例。

<navigator :url="'/pages/test/test?item='+ encodeURIComponent(JSON.stringify(item))"></navigator>
// 在test.vue页面接受参数
onLoad: function (option) 
	const item = JSON.parse(decodeURIComponent(option.item));

注意:

  • 页面跳转路径有层级限制,不能无限制跳转新页面
  • 跳转到 tabBar 页面只能使用 switchTab 跳转
  • 路由API的目标页面必须是在pages.json里注册的vue页面。如果想打开web url,在App平台可以使用 plus.runtime.openURL或web-view组件;H5平台使用 window.open;小程序平台使用web-view组件(url需在小程序的联网白名单中)。在hello uni-app中有个组件ulink.vue已对多端进行封装,可参考。

(5)小程序路由分包配置

因小程序有体积和资源加载限制,各家小程序平台提供了分包方式,优化小程序的下载和启动速度。
所谓的主包,即放置默认启动页面及 TabBar 页面,而分色则是根据 pages.json 的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,会把对应分包自动下整下来,下载完成后再进行展示,此时终端界面会有等待提示。

分包内静态文件示例

"subPackages": [
	"root": "pages/sub",
	"pages": [
		"path": "index/index"
	]
]

以上面的分包为例,放在每个分包root对应目录下的静态文件会被打包到此分包内。

预下载分包设置


	"pages": [
		"path": "pages/index/index",
		"style":  ...
	, 
		"path": "pages/login/login",
		"style":  ...
	],
	"subPackages": [
		"root": "pagesA",
		"pages": [
			"path": "list/list",
			"style":  ...
		]
	, 
		"root": "pagesB",
		"pages": [
			"path": "detail/detail",
			"style":  ...
		]
	],
	"preloadRule": 
		"pagesA/list/list": 
			"network": "all",
			"packages": ["__APP__"]
		,
		"pagesB/detail/detail": 
			"network": "all",
			"packages": ["pagesA"]
		
	


以上是关于android项目嵌套uniapp页面及交互的主要内容,如果未能解决你的问题,请参考以下文章

uniApp与原生Android 的交互(uni生成android壳子)

uniapp 打包Android的apk(原生APP-云打包),及发布测试

uniapp 打包Android的apk(原生APP-云打包),及发布测试

uniapp 打包Android的apk(原生APP-云打包),及发布测试

vue-cli搭建uniapp项目过程及踩坑记录

vue-cli搭建uniapp项目过程及踩坑记录