主頁 > 移動端開發 > Android集成友盟推送

Android集成友盟推送

2021-02-05 14:45:55 移動端開發

這幾天一直在做Android 訊息推送接入前的準備作業
特此在這里將自己在加載第三方推送時出現的問題以及詳細的接入步驟進行記錄,已免后者踩坑

目錄

  • 為什么選擇友盟推送?
  • 接入前的準備:
  • 打開官方示例
    • 初始化SDK
  • 離線推送
    • 廠商推送
    • 友盟廠商通道接入
    • 發送離線推送
    • 第一個坑
    • 第二個坑
  • 服務端代碼呼叫
  • 最最最重要的事

為什么選擇友盟推送?

在剛開始準備接入訊息推送時 首先我先想到的是極光推送,在大概看了一遍他們的接入流程并且根據他們的檔案做了一個demo后,因為是第一次接入推送,所以不太清楚在app離線情況下是如何接收到推送的流程,在積極和他們的業務人員溝通后也沒有得到一個我想要的回答 可能是因為自身原因(但是服務挺好的 會把你拉到一個相關的群聊里面 你可以和他們技術進行溝通 ),,,最后沒選擇激光推送的原因是他們的收費標準不清晰和兩個業務員溝通得到的答復都不太一樣 ,然后在學長的推薦下查看了友盟推送,對于友盟的第一印象就是感覺他們的檔案寫的很通俗易懂,并且非常棒的一點是還提供了視頻教學,雖然視頻長度很短,但是該表達的都表現出來了,還是很贊的,當然了,最后也是最重要的一點就是他們的推送是分為免費版和Pro版的,免費版的完全夠日常的使用,
在這里插入圖片描述

接入前的準備:

  1. 友盟官方接入檔案概述
    這里推薦大家使用最新版的SDK (Push SDK 6.1.0及之后才支持AndroidQ)
  2. 友盟推送產品后臺管理
  3. 友盟推送官方demo
  4. 新手引導 如果你還沒接觸過友盟推送,建議先看一下推送集成的流程

打開官方示例

當我們從官網下載好推送的demo,因為是一個完整的專案直接編譯即可,
編譯完成后先不著急運行,我們首先需要在友盟推送產品后臺管理新建一個新應用
在這里插入圖片描述

這里測驗階段你可以先填入當前demo的詳細包名,點擊確認添加后就會進入到配置向導界面
在這里插入圖片描述
這里你就可以拿到應用唯一的AppKey,Uming Message Secret,App Master Secret 這三個值很重要后期我們需要使用他們,

初始化SDK

進入我們的Android demo的MyApplication中,在UMConfigure.init()方法中分別填入我們的應用申請的Appkey和Umeng Message Secret對應資訊

 UMConfigure.init(this, "your appkey", "Umeng", UMConfigure.DEVICE_TYPE_PHONE, "umeng message secret");

然后運行一下我們的專案,拿到你設備專屬的device_token
在這里插入圖片描述
然后這時,進入我們的友盟推送后臺管理,點擊測驗模式->創建測驗任務
在這里插入圖片描述
在創建測驗任務最后一步點擊完成
在這里插入圖片描述
這時等待幾秒鐘后你的app就會接收到訊息通知,(請先確保當前demo在前臺)

在這里插入圖片描述
歐克,到這一步我們就算接入成功我們的測驗demo了,當然了這只算是剛剛開始,點擊該通知就會自動跳轉到我們的app中去,當然這里可以自定義我們收到通知后點擊通知會跳轉到的特定頁面或者指定url等等,這里可以在后續動作進行設定,當然你也可以傳遞引數,我們再來新建一個測驗任務測驗一下吧

在這里插入圖片描述
這里我們設定當用戶接收到通知點擊通知時跳轉到我們指定的頁面中,并且傳遞了引數,注意這里的指定頁面必須要填寫全路徑,
這時你是不是想,這就結束了,原來接入推送這么簡單啊 !
那你就錯了哦,當前我們接入的是在線推送哦,這里先清除你的當前demo的任務,使app處于離線狀態下,我們在來新建一個測驗任務,點擊發送你會發現接收不到該通知

離線推送

廠商推送

廠商推送指的就是手機硬體廠商提供的系統級別的推送服務,因為她是系統服務,隨手機開機后她就一直存在著,有效地保證了推送通道的高可用性,在網路暢通和推送訊息內容合法的情況下,通過廠商通道推送訊息給該型號手機,不論應用是否存活,都保證訊息推送到位,

友盟廠商通道接入

廠商通道接入詳細檔案
直接跟著檔案一步步走就行了,里面有詳細的接入步驟,效果圖以及鏈接
點此鏈接即可獲得神功!
這里需要注意的是:廠商推送賬號必須注冊為企業認證賬號

發送離線推送

其實這里和在線推送略有差別
在這里插入圖片描述
當我們集成好廠商通道后并完善我們的應用資訊后,在這里點擊勾選廠商通道,填入要打開的指定頁面(必填)點擊發送,當我們的app在離線狀態下也可以接收到訊息推送咯(這里上傳的是我集成demo),

在這里插入圖片描述

在這里插入圖片描述
app內接收到的引數:
在這里插入圖片描述

第一個坑

這里我在離線推送有問題的時候和友盟的人工客服溝通,他非常堅定地告訴我離線推送訊息后續行為只能設定為打開應用并且不可以傳參,當時我就懵了,我跟他說不能傳參我咋判斷跳轉到指定頁面的業務邏輯處理呢,他也沒給我具體的說法最后好像不了了之了

第二個坑

在我使用離線推送去推訊息時,我測驗了兩種情況,分別時app運行在前臺和清空后臺任務兩種情況,當我設定后續行為為打開應用推離線訊息時,app離線狀態下點擊通知會跳轉到指定界面(這里指的是勾選廠商推送后填寫跳轉的指定界面,不是行為動作跳轉指定界面),但是當app在前臺時點擊通知不會跳轉到指定界面,因為這里我們的后續行為設定的就是打開應用,我又和他們客服進行溝通,期間分別時和兩個客服進行了溝通,但是兩個給我的答復居然還都不一樣,并且說沒辦法,然后還說讓我推送時推送兩個,一個在線的一個離線的 ,我感覺他就是在瞎扯,我說他們技術在實作功能時肯定有考慮這一點,然后我強烈要求和他們技術進行溝通,最后也沒和他們技術進行溝通,不過最后也是找到了解決方法,就是在發送離線通知時,想行為動作也設定為跳轉到指定頁面,這樣發送離線訊息,不管是app離線還是在線都可以接收到資訊,并且點擊通知還可以跳轉到指定界面,最后也是了解到,當app離線時走的時廠商通道,在線時走的時友盟通道,所以為了實作不管app在不在線直接設定兩種都為跳轉到指定頁面的話都會執行這個結果,
這里忍不住吐槽友盟了,每個客服說的內容都相差太大,與實際不符,并且我們在接入時遇到的都是技術方面的問題,但是還不能和技術有一個很好的溝通,這點沒有極光做的好,不過檔案還是非常詳細的,

這就是詳細的接入步驟了,這里貼出我的跳轉指定頁面的activity

public class SecondActivity extends UmengNotifyClickActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        init();
    }

    private void init() {
        Bundle bun = getIntent().getExtras();
        if (bun != null) {
            Set<String> keySet = bun.keySet();
            for (String key : keySet) {
                String value = bun.getString(key);
                Log.i("testww", "#"+value);
                //Toast.makeText(this,"@"+value,Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);

    }

    @Override
    public void onMessage(Intent intent) {
        super.onMessage(intent);
        Log.i("unlineintent", "onMessage-------->");
        String body = intent.getStringExtra(AgooConstants.MESSAGE_BODY);
        Log.i("unlineintent", body);
    }
}

服務端代碼呼叫

這里有兩種方式在后臺呼叫,分別時呼叫API的方式和服務端呼叫
服務端下載地址
在這里插入圖片描述
這里推薦使用JAVA sdk的方式進行下載,因為其它兩個都太老了

當然你也可以選擇直接呼叫API, 詳情請戳->

這里我也下載了服務端代碼,并且進行了稍微的修改,在Demo.java檔案中新增了列播功能

       //列播
		public void sendAndroidListcast() throws Exception {
			AndroidListcast listcast = new AndroidListcast(appkey,appMasterSecret);
			// TODO Set your device token
			listcast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd,");
			listcast.setTicker( "通知欄提示文字");
			listcast.setTitle(  "通知標題");
			listcast.setText(   "通知文字描述");
			//點擊"通知"的后續行為,默認為打開app,
			//unicast.goAppAfterOpen();
			listcast.goActivityAfterOpen("com.example.wow.SecondActivity");
			listcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
			// TODO Set 'production_mode' to 'false' if it's a test device. 
			// For how to register a test device, please see the developer doc.
			//正式模式 默認為true 
			listcast.setProductionMode();
			// Set customized fields
			listcast.setExtraField("test", "helloworld");
			listcast.setExtraField("state", "ok");
			//廠商指定跳轉的activity
			listcast.setChannelActivity("com.example.wow.SecondActivity");
			//填寫小米channel_id  選填給推送進行分類別
			//unicast.setChannelProperties("abc");
		    //unicast.setChannelProperties("2882303761519015348");
			client.send(listcast);
		}

完整的Demo.java代碼

package push;


import org.json.JSONArray;
import org.json.JSONObject;

import push.android.AndroidBroadcast;
import push.android.AndroidCustomizedcast;
import push.android.AndroidFilecast;
import push.android.AndroidGroupcast;
import push.android.AndroidListcast;
import push.android.AndroidUnicast;
import push.ios.IOSBroadcast;
import push.ios.IOSCustomizedcast;
import push.ios.IOSFilecast;
import push.ios.IOSGroupcast;
import push.ios.IOSUnicast;

public class Demo {
	private String appkey = null;
	private String appMasterSecret = null;
	private String timestamp = null;
	private PushClient client = new PushClient();
	
	public Demo(String key, String secret) {
		try {
			appkey = key;
			appMasterSecret = secret;
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}
	//廣播:5次/分鐘(發送量10次/天)
	public void sendAndroidBroadcast() throws Exception {
		AndroidBroadcast broadcast = new AndroidBroadcast(appkey,appMasterSecret);
		broadcast.setTicker( "通知欄提示文字");
		broadcast.setTitle(  "我是廣播");
		broadcast.setText(   "是否全員接收");
		//broadcast.goAppAfterOpen();
		broadcast.goActivityAfterOpen("com.example.wow.SecondActivity");
		broadcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
		// TODO Set 'production_mode' to 'false' if it's a test device. 
		// For how to register a test device, please see the developer doc.
		broadcast.setProductionMode();
		// Set customized fields
		broadcast.setExtraField("test", "helloworld");
		//廠商通道相關引數
		broadcast.setChannelActivity("com.example.wow.SecondActivity");
		//broadcast.setChannelProperties("abc");
		client.send(broadcast);
	}
	//單播
	public void sendAndroidUnicast() throws Exception {
		AndroidUnicast unicast = new AndroidUnicast(appkey,appMasterSecret);
		// TODO Set your device token
		unicast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd");
		unicast.setTicker( "通知欄提示文字");
		unicast.setTitle(  "通知標題");
		unicast.setText(   "通知文字描述");
		//點擊"通知"的后續行為,默認為打開app,
		//unicast.goAppAfterOpen();
		unicast.goActivityAfterOpen("com.example.wow.SecondActivity");
		unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
		// TODO Set 'production_mode' to 'false' if it's a test device. 
		// For how to register a test device, please see the developer doc.
		//正式模式 默認為true 
		unicast.setProductionMode();
		// Set customized fields
		unicast.setExtraField("test", "helloworld");
		unicast.setExtraField("state", "ok");
		//廠商指定跳轉的activity
		unicast.setChannelActivity("com.example.wow.SecondActivity");
		//填寫小米channel_id  選填給推送進行分類別
		//unicast.setChannelProperties("abc");
	    //unicast.setChannelProperties("2882303761519015348");
		client.send(unicast);
	}
	
	
	
	    //列播
		public void sendAndroidListcast() throws Exception {
			AndroidListcast listcast = new AndroidListcast(appkey,appMasterSecret);
			// TODO Set your device token
			listcast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd,");
			listcast.setTicker( "通知欄提示文字");
			listcast.setTitle(  "通知標題");
			listcast.setText(   "通知文字描述");
			//點擊"通知"的后續行為,默認為打開app,
			//unicast.goAppAfterOpen();
			listcast.goActivityAfterOpen("com.example.wow.SecondActivity");
			listcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
			// TODO Set 'production_mode' to 'false' if it's a test device. 
			// For how to register a test device, please see the developer doc.
			//正式模式 默認為true 
			listcast.setProductionMode();
			// Set customized fields
			listcast.setExtraField("test", "helloworld");
			listcast.setExtraField("state", "ok");
			//廠商指定跳轉的activity
			listcast.setChannelActivity("com.example.wow.SecondActivity");
			//填寫小米channel_id  選填給推送進行分類別
			//unicast.setChannelProperties("abc");
		    //unicast.setChannelProperties("2882303761519015348");
			client.send(listcast);
		}
	
	//組播 用戶篩選條件,如用戶標簽、渠道等 不推薦使用
	public void sendAndroidGroupcast() throws Exception {
		AndroidGroupcast groupcast = new AndroidGroupcast(appkey,appMasterSecret);
		/*  TODO
		 *  Construct the filter condition:
		 *  "where": 
		 *	{
    	 *		"and": 
    	 *		[
      	 *			{"tag":"test"},
      	 *			{"tag":"Test"}
    	 *		]
		 *	}
		 */
		JSONObject filterJson = new JSONObject();
		JSONObject whereJson = new JSONObject();
		JSONArray tagArray = new JSONArray();
		JSONObject testTag = new JSONObject();
		JSONObject TestTag = new JSONObject();
		testTag.put("tag", "test");
		TestTag.put("tag", "Test");
		tagArray.put(testTag);
		tagArray.put(TestTag);
		whereJson.put("and", tagArray);
		filterJson.put("where", whereJson);

		groupcast.setFilter(filterJson);
		groupcast.setTicker( "Android groupcast ticker");
		groupcast.setTitle(  "中文的title");
		groupcast.setText(   "Android groupcast text");
		groupcast.goAppAfterOpen();
		groupcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
		groupcast.setChannelActivity("your channel activity");
		// TODO Set 'production_mode' to 'false' if it's a test device. 
		// For how to register a test device, please see the developer doc.
		groupcast.setProductionMode();
		//廠商通道相關引數
		groupcast.setChannelActivity("your channel activity");
		groupcast.setChannelProperties("abc");
		client.send(groupcast);
	}
	
	public void sendAndroidCustomizedcast() throws Exception {
		AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
		// TODO Set your alias here, and use comma to split them if there are multiple alias.
		// And if you have many alias, you can also upload a file containing these alias, then 
		// use file_id to send customized notification.
		customizedcast.setAlias("alias", "alias_type");
		customizedcast.setTicker( "Android customizedcast ticker");
		customizedcast.setTitle(  "中文的title");
		customizedcast.setText(   "Android customizedcast text");
		customizedcast.goAppAfterOpen();
		customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
		// TODO Set 'production_mode' to 'false' if it's a test device. 
		// For how to register a test device, please see the developer doc.
		customizedcast.setProductionMode();
		//廠商通道相關引數
		customizedcast.setChannelActivity("your channel activity");
		customizedcast.setChannelProperties("abc");
		client.send(customizedcast);
	}
	
	public void sendAndroidCustomizedcastFile() throws Exception {
		AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
		// TODO Set your alias here, and use comma to split them if there are multiple alias.
		// And if you have many alias, you can also upload a file containing these alias, then 
		// use file_id to send customized notification.
		String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb"+"\n"+"alias");
		customizedcast.setFileId(fileId, "alias_type");
		customizedcast.setTicker( "Android customizedcast ticker");
		customizedcast.setTitle(  "中文的title");
		customizedcast.setText(   "Android customizedcast text");
		customizedcast.goAppAfterOpen();
		customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
		// TODO Set 'production_mode' to 'false' if it's a test device. 
		// For how to register a test device, please see the developer doc.
		customizedcast.setProductionMode();
		//廠商通道相關引數
		customizedcast.setChannelActivity("your channel activity");
		customizedcast.setChannelProperties("abc");
		client.send(customizedcast);
	}
	
	public void sendAndroidFilecast() throws Exception {
		AndroidFilecast filecast = new AndroidFilecast(appkey,appMasterSecret);
		// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens 
		String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
		filecast.setFileId( fileId);
		filecast.setTicker( "Android filecast ticker");
		filecast.setTitle(  "中文的title");
		filecast.setText(   "Android filecast text");
		filecast.goAppAfterOpen();
		filecast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
		//廠商通道相關引數
		filecast.setChannelActivity("your channel activity");
		filecast.setChannelProperties("abc");
		client.send(filecast);
	}
	
	public void sendIOSBroadcast() throws Exception {
		IOSBroadcast broadcast = new IOSBroadcast(appkey,appMasterSecret);
        //alert值設定為字串
		//broadcast.setAlert("IOS 廣播測驗");
		//alert的值設定為字典
		broadcast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
		broadcast.setBadge( 0);
		broadcast.setSound( "default");
		// TODO set 'production_mode' to 'true' if your app is under production mode
		broadcast.setTestMode();
		// Set customized fields
		broadcast.setCustomizedField("test", "helloworld");
		client.send(broadcast);
	}
	
	public void sendIOSUnicast() throws Exception {
		IOSUnicast unicast = new IOSUnicast(appkey,appMasterSecret);
		// TODO Set your device token
		unicast.setDeviceToken( "your device_token");
		//alert值設定為字串
		//unicast.setAlert("IOS 單播測驗");
		//alert的值設定為字典
		unicast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
		unicast.setBadge( 0);
		unicast.setSound( "default");
		// TODO set 'production_mode' to 'true' if your app is under production mode
		unicast.setTestMode();
		// Set customized fields
		unicast.setCustomizedField("test", "helloworld");
		client.send(unicast);
	}

	
	public void sendIOSGroupcast() throws Exception {
		IOSGroupcast groupcast = new IOSGroupcast(appkey,appMasterSecret);
		/*  TODO
		 *  Construct the filter condition:
		 *  "where": 
		 *	{
    	 *		"and": 
    	 *		[
      	 *			{"tag":"iostest"}
    	 *		]
		 *	}
		 */
		JSONObject filterJson = new JSONObject();
		JSONObject whereJson = new JSONObject();
		JSONArray tagArray = new JSONArray();
		JSONObject testTag = new JSONObject();
		testTag.put("tag", "iostest");
		tagArray.put(testTag);
		whereJson.put("and", tagArray);
		filterJson.put("where", whereJson);
		System.out.println(filterJson.toString());
		
		// Set filter condition into rootJson
		groupcast.setFilter(filterJson);
		//groupcast.setAlert("IOS 組播測驗");
		//alert的值設定為字典
		groupcast.setAlert("今日天氣" , "subtitle" , "今日可能下雨🌂");
		groupcast.setBadge( 0);
		groupcast.setSound( "default");
		// TODO set 'production_mode' to 'true' if your app is under production mode
		groupcast.setTestMode();
		client.send(groupcast);
	}
	
	public void sendIOSCustomizedcast() throws Exception {
		IOSCustomizedcast customizedcast = new IOSCustomizedcast(appkey,appMasterSecret);
		// TODO Set your alias and alias_type here, and use comma to split them if there are multiple alias.
		// And if you have many alias, you can also upload a file containing these alias, then 
		// use file_id to send customized notification.
		customizedcast.setAlias("alias", "alias_type");
		//customizedcast.setAlert("IOS 個性化測驗");
		//alert的值設定為字典
		customizedcast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
		customizedcast.setBadge( 0);
		customizedcast.setSound( "default");
		// TODO set 'production_mode' to 'true' if your app is under production mode
		customizedcast.setTestMode();
		client.send(customizedcast);
	}
	
	public void sendIOSFilecast() throws Exception {
		IOSFilecast filecast = new IOSFilecast(appkey,appMasterSecret);
		// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens 
		String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
		filecast.setFileId( fileId);
		//filecast.setAlert("IOS 檔案播測驗");
		//alert的值設定為字典
		filecast.setAlert("今日天氣" , "" , "今日可能下雨🌂");
		filecast.setBadge( 0);
		filecast.setSound( "default");
		// TODO set 'production_mode' to 'true' if your app is under production mode
		filecast.setTestMode();
		client.send(filecast);
	}
	
	public static void main(String[] args) {
		// TODO set your appkey and master secret here
		Demo demo = new Demo("your appkey", "master secret");
		try {
			//單播 處理一個設備的訊息推送 推薦 
			//demo.sendAndroidUnicast();
			
			//列播 處理2個以上500個以下的訊息推送
			demo.sendAndroidListcast();
			
			//廣播  5次/分鐘(發送量10次/天) 向所有安裝該app的用戶發送推送  推薦
			//demo.sendAndroidBroadcast();
			
			//demo.sendAndroidCustomizedcastFile();
			
			//組播 不推薦使用
			//demo.sendAndroidGroupcast();
			//不推薦
			//* demo.sendAndroidCustomizedcast();
			//* demo.sendAndroidFilecast();
			
			
			
			//demo.sendIOSUnicast();
			/* TODO these methods are all available, just fill in some fields and do the test
			 * demo.sendAndroidCustomizedcastFile();
			 * demo.sendAndroidBroadcast();
			 * demo.sendAndroidGroupcast();
			 * demo.sendAndroidCustomizedcast();
			 * demo.sendAndroidFilecast();
			 * 
			 * demo.sendIOSBroadcast();
			 * demo.sendIOSUnicast();
			 * demo.sendIOSGroupcast();
			 * demo.sendIOSCustomizedcast();
			 * demo.sendIOSFilecast();
			 */
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	

}

看注釋
以及還有新增的列播類

package push.android;

import push.AndroidNotification;

public class AndroidListcast extends AndroidNotification {
	public AndroidListcast(String appkey,String appMasterSecret) throws Exception {
			setAppMasterSecret(appMasterSecret);
			setPredefinedKeyValue("appkey", appkey);
			this.setPredefinedKeyValue("type", "listcast");	
	}
	
	public void setDeviceToken(String tokens) throws Exception {
    	setPredefinedKeyValue("device_tokens", tokens);
    }

}

最最最重要的事

歐克,到這里友盟推送的集成就算完成咯,這段關系只能到這了,如果非要說點什么的話,那就是愛過~

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

標籤:其他

上一篇:axios請求封裝--封裝api

下一篇:安卓基礎學習 Day23 |HTTP框架-OKHttp3

標籤雲
其他(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