主頁 > 移動端開發 > js bridge 實作原理

js bridge 實作原理

2021-02-01 12:58:18 移動端開發

原文鏈接 https://www.cnblogs.com/dailc/p/5931324.html#hybrid_2_2

說明

JSBridge實作原理

目錄

  • 前言
    • 參考來源
    • 前置技術要求
    • 楔子
  • 原理概述
    • 簡介
    • url scheme介紹
  • 實作流程
    • 實作思路
    • 第一步:設計出一個Native與JS互動的全域橋物件
    • 第二步:JS如何呼叫Native
    • 第三步:Native如何得知api被呼叫
    • 第四步:分析url-引數和回呼的格式
    • 第五步:Native如何呼叫JS
    • 第六步:H5中api方法的注冊以及格式
  • 進一步完善JSBridge方案
    • 思路
    • 實作
    • 注意
  • 完整的JSBridge
    • 完整呼叫流程圖
    • 另外實作:不采用url scheme方式
  • 實作示例
    • 示例說明
    • 實作原始碼

前言

參考來源

前人栽樹,后臺乘涼,本文參考了以下來源

  • github-WebViewJavascriptBridge
  • JSBridge-Web與Native互動之iOS篇
  • Ios Android Hybrid app 與 Js Bridge
  • Hybrid APP架構設計思路
  • 【Android】如何寫一個JsBridge
  • IOS之URL Scheme的使用
  • marcuswestin/WebViewJavascriptBridge

前置技術要求

閱讀本文前,建議先閱讀以下文章

  • Hybrid APP基礎篇(三)->Hybrid APP之Native和H5頁面互動原理

楔子

上文中簡單的介紹了JSBridge,以及為什么要用JSBridge,本文詳細介紹它的實作原理

原理概述

簡介

JSBridge是Native代碼與JS代碼的通信橋梁,目前的一種統一方案是:H5觸發url scheme->Native捕獲url scheme->原生分析,執行->原生呼叫h5,如下圖

https://dailc.github.io/staticResource/blog/hybrid/jsbridge/img_hybrid_base_jsbridgePrinciple_1.png

url scheme介紹

上圖中有提到url scheme這個概念,那這到底是什么呢?

  • url scheme是一種類似于url的鏈接,是為了方便app直接互相呼叫設計的

    具體為,可以用系統的OpenURI打開一個類似于url的鏈接(可拼入引數),然后系統會進行判斷,如果是系統的url scheme,則打開系統應用,否則找看是否有app注冊這種scheme,打開對應app

    需要注意的是,這種scheme必須原生app注冊后才會生效,如微信的scheme為(weixin://)

  • 而本文JSBridge中的url scheme則是仿照上述的形式的一種方式

    具體為,app不會注冊對應的scheme,而是由前端頁面通過某種方式觸發scheme(如用iframe.src),然后Native用某種方法捕獲對應的url觸發事件,然后拿到當前的觸發url,根據定義好的協議,分析當前觸發了那種方法,然后根據定義來執行等

實作流程

基于上述的基本原理,現在開始設計一種JSBridge的實作

實作思路

要實作JSBridge,我們可以進行關鍵步驟分析

  • 第一步:設計出一個Native與JS互動的全域橋物件
  • 第二步:JS如何呼叫Native
  • 第三步:Native如何得知api被呼叫
  • 第四步:分析url-引數和回呼的格式
  • 第五步:Native如何呼叫JS
  • 第六步:H5中api方法的注冊以及格式

如下圖:

https://dailc.github.io/staticResource/blog/hybrid/jsbridge/img_hybrid_base_jsbridgePrinciple_3.png

第一步:設計出一個Native與JS互動的全域橋物件

我們規定,JS和Native之間的通信必須通過一個H5全域物件JSbridge來實作,該物件有如下特點

  • 該物件名為"JSBridge",是H5頁面中全域物件window的一個屬性

    var JSBridge = window.JSBridge || (window.JSBridge = {});
    					
    
  • 該物件有如下方法

    • registerHandler( String,Function )H5呼叫 注冊本地JS方法,注冊后Native可通過JSBridge呼叫,呼叫后會將方法注冊到本地變數messageHandlers
    • callHandler( String,JSON,Function )H5呼叫 呼叫原生開放的api,呼叫后實際上還是本地通過url scheme觸發,呼叫時會將回呼id存放到本地變數responseCallbacks
    • _handleMessageFromNative( JSON )Native呼叫 原生呼叫H5頁面注冊的方法,或者通知H5頁面執行回呼方法
  • 如圖

    https://dailc.github.io/staticResource/blog/hybrid/jsbridge/img_hybrid_base_jsbridgePrinciple_2.png

第二步:JS如何呼叫Native

在第一步中,我們定義好了全域橋物件,可以我們是通過它的callHandler方法來呼叫原生的,那么它內部經歷了一個怎么樣的程序呢?如下

callHandler函式內部實作程序

在執行callHandler時,內部經歷了以下步驟:

  • (1)判斷是否有回呼函式,如果有,生成一個回呼函式id,并將id和對應回呼添加進入回呼函式集合responseCallbacks

  • (2)通過特定的引數轉換方法,將傳入的資料,方法名一起,拼接成一個url scheme

    //url scheme的格式如
    //基本有用資訊就是后面的callbackId,handlerName與data
    //原生捕獲到這個scheme后會進行分析
    var uri = CUSTOM_PROTOCOL_SCHEME://API_Name:callbackId/handlerName?data
    					
    
  • (3)使用內部早就創建好的一個隱藏iframe來觸發scheme

    //創建隱藏iframe程序
    var messagingIframe = document.createElement('iframe');
    messagingIframe.style.display = 'none';
    document.documentElement.appendChild(messagingIframe);
    
    //觸發scheme
    messagingIframe.src = uri;
    					
    

    注意,正常來說是可以通過window.location.href達到發起網路請求的效果的,但是有一個很嚴重的問題,就是如果我們連續多次修改window.location.href的值,在Native層只能接收到最后一次請求,前面的請求都會被忽略掉,所以JS端發起網路請求的時候,需要使用iframe,這樣就可以避免這個問題,---引自參考來源

第三步:Native如何得知api被呼叫

在上一步中,我們已經成功在H5頁面中觸發scheme,那么Native如何捕獲scheme被觸發呢?

根據系統不同,Android和iOS分別有自己的處理方式

Android捕獲url scheme

在Android中(WebViewClient里),通過shouldoverrideurlloading可以捕獲到url scheme的觸發

public boolean shouldOverrideUrlLoading(WebView view, String url){
	//讀取到url后自行進行分析處理
	
	//如果回傳false,則WebView處理鏈接url,如果回傳true,代表WebView根據程式來執行url
	return true;
}
			

另外,Android中也可以不通過iframe.src來觸發scheme,android中可以通過window.prompt(uri, "");來觸發scheme,然后Native中通過重寫WebViewClient的onJsPrompt來獲取uri

iOS捕獲url scheme

iOS中,UIWebView有個特性:在UIWebView內發起的所有網路請求,都可以通過delegate函式在Native層得到通知,這樣,我們可以在webview中捕獲url scheme的觸發(原理是利用 shouldStartLoadWithRequest)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = [request URL];
     
    NSString *requestString = [[request URL] absoluteString];
    //獲取利潤url scheme后自行進行處理
			

之后Native捕獲到了JS呼叫的url scheme,接下來就該到下一步分析url了

第四步:分析url-引數和回呼的格式

在前面的步驟中,Native已經接收到了JS呼叫的方法,那么接下來,原生就應該按照定義好的資料格式來決議資料了

url scheme的格式 前面已經提到,Native接收到Url后,可以按照這種格式將回呼引數id、api名、引數提取出來,然后按如下步驟進行

  • (1)根據api名,在本地找尋對應的api方法,并且記錄該方法執行完后的回呼函式id

  • (2)根據提取出來的引數,根據定義好的引數進行轉化

    如果是JSON格式需要手動轉換,如果是String格式直接可以使用

  • (3)原生本地執行對應的api功能方法

  • (4)功能執行完畢后,找到這次api呼叫對應的回呼函式id,然后連同需要傳遞的引數資訊,組裝成一個JSON格式的引數

    回呼的JSON格式為:{responseId:回呼id,responseData:回呼資料}

    • responseId String型 H5頁面中對應需要執行的回呼函式的id,在H5中生成url scheme時就已經產生
    • responseData JSON型 Native需要傳遞給H5的回呼資料,是一個JSON格式: {code:(整型,呼叫是否成功,1成功,0失敗),result:具體需要傳遞的結果資訊,可以為任意型別,msg:一些其它資訊,如呼叫錯誤時的錯誤資訊}
  • (5)通過JSBridge通知H5頁面回呼

    參考 Native如何呼叫JS

第五步:Native如何呼叫JS

到了這一步,就該Native通過JSBridge呼叫H5的JS方法或者通知H5進行回呼了,具體如下

//將回呼資訊傳給H5
JSBridge._handleMessageFromNative(messageJSON);						
			

如上,實際上是通過JSBridge的_handleMessageFromNative傳遞資料給H5,其中的messageJSON資料格式根據兩種不同的型別,有所區別,如下

Native通知H5頁面進行回呼

資料格式為: Native通知H5回呼的JSON格式

Native主動呼叫H5方法

Native主動呼叫H5方法時,資料格式是:{handlerName:api名,data:資料,callbackId:回呼id}

  • handlerName String型 需要呼叫的,h5中開放的api的名稱
  • data JSON型 需要傳遞的資料,固定為JSON格式(因為我們固定H5中注冊的方法接收的第一個引數必須是JSON,第二個是回呼函式)
  • callbackId String型 原生生成的回呼函式id,h5執行完畢后通過url scheme通知原生api成功執行,并傳遞引數

注意,這一步中,如果Native呼叫的api是h5沒有注冊的,h5頁面上會有對應的錯誤提示,

另外,H5呼叫Native時,Native處理完畢后一定要及時通知H5進行回呼,要不然這個回呼函式不會自動銷毀,多了后會引發記憶體泄漏,

第六步:H5中api方法的注冊以及格式

前面有提到Native主動呼叫H5中注冊的api方法,那么h5中怎么注冊供原生呼叫的api方法呢?格式又是什么呢?如下

H5中注冊供原生呼叫的API

//注冊一個測驗函式
JSBridge.registerHandler('testH5Func',function(data,callback){
	alert('測驗函式接收到資料:'+JSON.stringify(data));
	callback&&callback('測驗回傳資料...');
});				
			

如上述代碼為注冊一個供原生呼叫的api

H5中注冊的API格式注意

如上代碼,注冊的api引數是(data,callback)

其中第一個data即原生傳過來的資料,第二個callback是內部封裝過一次的,執行callback后會觸發url scheme,通知原生獲取回呼資訊

進一步完善JSBridge方案

在前文中,已經完成了一套JSBridge方案,這里,在介紹下如何完善這套方案

思路

github上有一個開源專案,它里面的JSBridge做法在iOS上進一步優化了,所以參考他的做法,這里進一步進行了完善,地址marcuswestin/WebViewJavascriptBridge

大致思路就是

  • h5呼叫Native的關鍵步驟進行拆分,由以前的直接傳遞url scheme變為傳遞一個統一的url scheme,然后Native主動獲取傳遞的引數

    完善以前: H5呼叫Native->將所有引陣列裝成為url scheme->原生捕獲scheme,進行分析

    完善以后: H5呼叫Native->將所有引數存入本地陣列->觸發一個固定的url scheme->原生捕獲scheme->原生通過JSBridge主動獲取引數->進行分析

實作

這種完善后的流程和以前有所區別,如下

JSBridge物件圖解

https://dailc.github.io/staticResource/blog/hybrid/jsbridge/img_hybrid_base_jsbridgePrinciple_4.png

JSBridge實作完整流程

https://dailc.github.io/staticResource/blog/hybrid/jsbridge/img_hybrid_base_jsbridgePrinciple_5.png

注意

由于這次完善的核心是:Native主動呼叫JS函式,并獲取回傳值,而在Android4.4以前,Android是沒有這個功能的,所以并不完全適用于Android

所以一般會進行一個兼容處理,Android中采用以前的scheme傳法,iOS使用完善后的方案(也便于4.4普及后后續的完善)

完整的JSBridge

上述分析了JSBridge的實作流程,那么實際專案中,我們就應該結合上述兩種,針對Android和iOS的不同情況,統一出一種完整的方案,如下

完整呼叫流程圖

https://dailc.github.io/staticResource/blog/hybrid/jsbridge/img_hybrid_base_jsbridgePrinciple_6.png

如上圖,結合上述方案后有了一套統一JSBridge方案

另外實作:不采用url scheme方式

前面提到的JSBridge都是基于url scheme的,但其實如果不考慮Android4.2以下,iOS7以下,其實也可以用另一套方案的,如下

  • Native呼叫JS的方法不變

  • JS呼叫Native是不再通過觸發url scheme,而是采用自帶的互動,比如

    Android中,原生通過 addJavascriptInterface開放一個統一的api給JS呼叫,然后將觸發url scheme步驟變為呼叫這個api,其余步驟不變(相當于以前是url接收引數,現在變為api函式接收引數)

    iOS中,原生通過JavaScriptCore里面的方法來注冊一個統一api,其余和Android中一樣(這里就不需要主動獲取引數了,因為引數可以直接由這個函式統一接收)

當然了,這只是一種可行的方案,多一種選擇而已,具體實作流程請參考前面系列文章,本文不再贅述

實作示例

示例說明

本文中包括兩個示例,一個是基礎版本的JSBridge實作,一個是完整版本的JSBridge實作(包括JS,Android,iOS實作等)

實作原始碼

基礎版本的JSBridge

這里只介紹JS的實作,具體Android,iOS實作請參考完整版本,實作如下

(function() {
	(function() {
		var hasOwnProperty = Object.prototype.hasOwnProperty;
		var JSBridge = window.JSBridge || (window.JSBridge = {});
		//jsbridge協議定義的名稱
		var CUSTOM_PROTOCOL_SCHEME = 'CustomJSBridge';
		//最外層的api名稱
		var API_Name = 'namespace_bridge';
		//進行url scheme傳值的iframe
		var messagingIframe = document.createElement('iframe');
		messagingIframe.style.display = 'none';
		messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;
		document.documentElement.appendChild(messagingIframe);

		//定義的回呼函式集合,在原生呼叫完對應的方法后,會執行對應的回呼函式id
		var responseCallbacks = {};
		//唯一id,用來確保每一個回呼函式的唯一性
		var uniqueId = 1;
		//本地注冊的方法集合,原生只能呼叫本地注冊的方法,否則會提示錯誤
		var messageHandlers = {};

		//實際暴露給原生呼叫的物件
		var Inner = {
			/**
			 * @description 注冊本地JS方法通過JSBridge給原生呼叫
			 * 我們規定,原生必須通過JSBridge來呼叫H5的方法
			 * 注意,這里一般對本地函式有一些要求,要求第一個引數是data,第二個引數是callback
			 * @param {String} handlerName 方法名
			 * @param {Function} handler 對應的方法
			 */
			registerHandler: function(handlerName, handler) {
				messageHandlers[handlerName] = handler;
			},
			/**
			 * @description 呼叫原生開放的方法
			 * @param {String} handlerName 方法名
			 * @param {JSON} data 引數
			 * @param {Function} callback 回呼函式
			 */
			callHandler: function(handlerName, data, callback) {
				//如果沒有 data
				if(arguments.length == 3 && typeof data == 'function') {
					callback = data;
					data = null;
				}
				_doSend({
					handlerName: handlerName,
					data: data
				}, callback);
			},
			/**
			 * @description 原生呼叫H5頁面注冊的方法,或者呼叫回呼方法
			 * @param {String} messageJSON 對應的方法的詳情,需要手動轉為json
			 */
			_handleMessageFromNative: function(messageJSON) {
				setTimeout(_doDispatchMessageFromNative);
				/**
				 * @description 處理原生過來的方法
				 */
				function _doDispatchMessageFromNative() {
					var message;
					try {
						if(typeof messageJSON === 'string'){
							message = JSON.parse(messageJSON);
						}else{
							message = messageJSON;
						}	
					} catch(e) {
						//TODO handle the exception
						console.error("原生呼叫H5方法出錯,傳入引數錯誤");
						return;
					}

					//回呼函式
					var responseCallback;
					if(message.responseId) {
						//這里規定,原生執行方法完畢后準備通知h5執行回呼時,回呼函式id是responseId
						responseCallback = responseCallbacks[message.responseId];
						if(!responseCallback) {
							return;
						}
						//執行本地的回呼函式
						responseCallback(message.responseData);
						delete responseCallbacks[message.responseId];
					} else {
						//否則,代表原生主動執行h5本地的函式
						if(message.callbackId) {
							//先判斷是否需要本地H5執行回呼函式
							//如果需要本地函式執行回呼通知原生,那么在本地注冊回呼函式,然后再呼叫原生
							//回呼資料有h5函式執行完畢后傳入
							var callbackResponseId = message.callbackId;
							responseCallback = function(responseData) {
								//默認是呼叫EJS api上面的函式
								//然后接下來原生知道scheme被呼叫后主動獲取這個資訊
								//所以原生這時候應該會進行判斷,判斷對于函式是否成功執行,并接收資料
								//這時候通訊完畢(由于h5不會對回呼添加回呼,所以接下來沒有通信了)
								_doSend({
									handlerName: message.handlerName,
									responseId: callbackResponseId,
									responseData: responseData
								});
							};
						}

						//從本地注冊的函式中獲取
						var handler = messageHandlers[message.handlerName];
						if(!handler) {
							//本地沒有注冊這個函式
						} else {
							//執行本地函式,按照要求傳入資料和回呼
							handler(message.data, responseCallback);
						}
					}
				}
			}

		};
		/**
		 * @description JS呼叫原生方法前,會先send到這里進行處理
		 * @param {JSON} message 呼叫的方法詳情,包括方法名,引數
		 * @param {Function} responseCallback 呼叫完方法后的回呼
		 */
		function _doSend(message, responseCallback) {
			if(responseCallback) {
				//取到一個唯一的callbackid
				var callbackId = Util.getCallbackId();
				//回呼函式添加到集合中
				responseCallbacks[callbackId] = responseCallback;
				//方法的詳情添加回呼函式的關鍵標識
				message['callbackId'] = callbackId;
			}

			//獲取 觸發方法的url scheme
			var uri = Util.getUri(message);
			//采用iframe跳轉scheme的方法
			messagingIframe.src = uri;
		}

		var Util = {
			getCallbackId: function() {
				//如果無法決議埠,可以換為Math.floor(Math.random() * (1 << 30));
				return 'cb_' + (uniqueId++) + '_' + new Date().getTime();
			},
			//獲取url scheme
			//第二個引數是兼容android中的做法
			//android中由于原生不能獲取JS函式的回傳值,所以得通過協議傳輸
			getUri: function(message) {
				var uri = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;
				if(message) {
					//回呼id作為埠存在
					var callbackId, method, params;
					if(message.callbackId) {
						//第一種:h5主動呼叫原生
						callbackId = message.callbackId;
						method = message.handlerName;
						params = message.data;
					} else if(message.responseId) {
						//第二種:原生呼叫h5后,h5回呼
						//這種情況下需要原生自行分析傳過去的port是否是它定義的回呼
						callbackId = message.responseId;
						method = message.handlerName;
						params = message.responseData;
					}
					//引數轉為字串
					params = this.getParam(params);
					//uri 補充
					uri += ':' + callbackId + '/' + method + '?' + params;
				}

				return uri;
			},
			getParam: function(obj) {
				if(obj && typeof obj === 'object') {
					return JSON.stringify(obj);
				} else {
					return obj || '';
				}
			}
		};
		for(var key in Inner) {
			if(!hasOwnProperty.call(JSBridge, key)) {
				JSBridge[key] = Inner[key];
			}
		}

	})();

	//注冊一個測驗函式
	JSBridge.registerHandler('testH5Func', function(data, callback) {
		alert('測驗函式接收到資料:' + JSON.stringify(data));
		callback && callback('測驗回傳資料...');
	});
	/*
	 ***************************API********************************************
	 * 開放給外界呼叫的api
	 * */
	window.jsapi = {};
	/**
	 ***app 模塊 
	 * 一些特殊操作
	 */
	jsapi.app = {
		/**
		 * @description 測驗函式
		 */
		testNativeFunc: function() {
			//呼叫一個測驗函式
			JSBridge.callHandler('testNativeFunc', {}, function(res) {
				callback && callback(res);
			});
		}
	};
})();				
			

完整版本的JSBridge

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/255251.html

標籤:其他

上一篇:android博客導航總結,以及個人常用android免費學習干貨(文章,視頻,矢量圖,字體等)資源分享?

下一篇:需求

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more