Android接入抖音分享踩坑之旅

前言

抖音做爲日活量過億的產品,在今年年初,也終於上線了抖音開放平臺,目前支持app接入登陸與分享。app經過抖音受權獲取用戶信息;分享視頻並進行處理,提升app在抖音的曝光度。java

恰好項目有個新需求,須要集成抖音登陸與分享。抖音開發者文檔android

本覺得不就是接個SDK嘛,溼溼水啦!可是bug總與我相伴!且聽我慢慢道來。c#

導入依賴

一、在項目根目錄build.gradle裏添加maven:api

allprojects {
    repositories {
        ……
        maven { url 'https://dl.bintray.com/aweme-open-sdk-team/public' }
    }
}
複製代碼

二、接着在app目錄的build.gradle添加依賴:bash

dependencies {
    implementation 'com.bytedance.ies.ugc.aweme:open-sdk:0.0.1.3'
}
複製代碼

別忘了在manifest添加權限並處理,最後同步項目微信

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
複製代碼

集成抖音分享

一、在Application中,onCreate方法下初始化TikTokOpenApiFactoryapp

String clientkey = "xxx"; // 到開發者網站申請並替換
TikTokOpenApiFactory.init(new TikTokOpenConfig(clientkey));
複製代碼

二、分享視頻maven

//視頻文件路徑
private ArrayList<String> mUri = new ArrayList<>();
mUri.add("xxx.video-path");

// 初始化api,須要傳入targetApp
TiktokOpenApi tiktokOpenApi = 
    TikTokOpenApiFactory.create(this, TikTokConstants.TARGET_APP.AWEME);

// 初始化Share
Share.Request request = new Share.Request();
TikTokVideoObject videoObject = new TikTokVideoObject();
videoObject.mVideoPaths = mUri;
TikTokMediaContent content = new TikTokMediaContent();
content.mMediaObject = videoObject;
request.mMediaContent = content;
//配置完成後,調用share方法喚起抖音app
tiktokOpenApi.share(request);
複製代碼

三、接收回調ide

兩種方式接收回調信息:測試

(1)在包名下建立.tiktokapi.TikTokEntryActivity,初始化TTOpenApi,實現 TikTokApiEventHandler接口,在onResp方法中回調結果。(和微信回調相似)

(2)自定義接收回調全路徑,好比須要回調的activity路徑爲:

com.douyin.share.TikTokEntryActivity
複製代碼

則在前面傳分享參數時指定回調全路徑:

request.callerLocalEntry = com.douyin.share.TikTokEntryActivity
複製代碼

回調activity實現TikTokApiEventHandler接口,並在manifest中註冊activity,添加android:exported="true",而後在onResp方法接收回調:

public void onResp(BaseResp resp) {
     if (resp.getType() == TikTokConstants.ModeType.SHARE_CONTENT_TO_TT_RESP) {
         switch (resp.errorCode){
                case TikTokConstants.BaseErrorCode.OK:
                    Toast.makeText(this, "分享成功",Toast.LENGTH_SHORT).show();
                    break;
                case TikTokConstants.BaseErrorCode.ERROR_UNKNOW:
                    Toast.makeText(this, "未知錯誤",Toast.LENGTH_SHORT).show();
                    break;
                case TikTokConstants.BaseErrorCode.ERROR_CANCEL:
                    Toast.makeText(this, "取消分享",Toast.LENGTH_SHORT).show();
                    break;
            }
     }
     finish();
}
複製代碼

OK!至此咱們就能夠接收分享回調了!心情別提有多愉快!! 來看看效果:

what! 取消分享後,雖然彈出了Toast,可是並無回到咱們的app,而是留在抖音。這就坑了!微信取消分享後均可以回到app,可是抖音就不行。估計是我哪裏配置不對,去扒官方文檔,在FQA裏發現了這樣一段話:
就是說,抖音在回調activity的時候,這個類是經過singleInstance啓動的,若是想回到應用,也有辦法,注意畫紅線的部分,「啓動本身app的類跳回本身app的棧」,我將信將疑的照作了,在onResp方法啓動MainActivity

public void onResp(BaseResp resp) {
     if (resp.getType() == TikTokConstants.ModeType.SHARE_CONTENT_TO_TT_RESP) {
         ……
         //添加這行代碼
         startActivity(new Intent(this, MainActivity.class));
     }
     finish();
}
複製代碼

改完後咱們再來跑一遍:

沒毛病,好像是成功了!?嗯?有點怪,頁面啓動分享的按鈕怎麼不見了!

我繼續按返回鍵操做:

what!按下返回鍵後,又回到了抖音主界面,再接着按返回鍵,纔回到咱們的app(有啓動分享的按鈕)。

這就坑了,文檔不是說啓動本身app的類就能回到本身app的棧嗎?我好奇的打開了手機任務棧,發現:

坑!怎麼我本身app的界面跑到抖音的進程裏了?

分析

咱們來捋一捋這些場景,並結合官方文檔來分析。文檔描述,tiktok回調這個類是經過singleInstance的,即抖音回調activity的時候,是經過singleInstance啓動TikTokEntryActivity的,這個時候的TikTokEntryActivity運行在獨立的任務棧裏,屬於前臺任務;當調用到TikTokEntryActivity的onResp方法,執行到startActivity(new Intent(this,MainActivity.class)),啓動MainActivity並finish本身,這個時候抖音的任務棧屬於前臺任務棧,那麼天然而然的,新啓動的MainActivity就依附在抖音的任務棧上。接着再按返回鍵,退出了抖音的任務棧,最後纔回到本身app的任務棧。

探索方案

OK!知道了緣由,對應的解決方案也就有了。在TikTokEntryActivity調用finish後,咱們只須要將MainActivity拉回本身app的任務棧,那麼不就能夠搞定了嗎?

想法是好,可是還會有兩個問題:

(1)如何將MainActivity拉回本身app的任務棧?

(2)接收回調後,不必定是跳轉到MainActivity,而是怎麼回到啓動分享的那個activity?

第一個問題好解決,把MainActivity的啓動模式設置爲singleTask就好了; 第二個問題,怎麼回到啓動分享的那個activity?好比一個實際的場景,A是根activity,A能夠啓動B或者啓動C,而後B和C均可以喚起抖音分享,那麼分享後回到哪一個activity得知道,也就是須要知道棧頂activity。就跟喚起微信,取消分享的場景同樣(不知道抖音爲何不作成和微信同樣的處理方式,還須要開發者額外處理)。

把問題1和2結合起來就是: 接收回調後,如何跳轉到啓動分享的那個activity?(即本身app棧的棧頂activity)

(1)從shareSDK找線索

具體怎麼作?搜索了一番,發現shareSDK是支持抖音分享的,能夠扒它們抖音SDK模塊的jar包看看是怎麼處理的? 下載shareSDK官方demo,用Android Studio打開後,在依賴包目錄下找到了關於抖音模塊的代碼:

DouYinHandlerActivity,沒錯,就是這個類,其中有一個方法引發了個人注意:

很明顯,shareSDK的處理是在onDestroy方法,建立Intent,並經過隱式啓動來跳轉到本身app的任務棧。action的值表示須要在manifest對應的activity去添加,flags被混淆成了數字,反編譯後發現是FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP,對應

Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP
複製代碼

找到辦法後我欣喜若狂,趕忙參照該方法處理。發現能夠跳轉到本身app,可是有時候會失效!後來還下載了shareSDK的apk測試,也發現偶爾會有失效的問題。看來這個辦法不夠完美,只能繼續尋找方案。

……

(2)從競品找線索

而後,在抖音開放平臺官網發現,輕顏相機是目前市面上集成了抖音SDK的app,我趕忙下載測試:

能夠看到,輕顏相機是能夠回到本身app的。那麼輕顏相機是怎麼作的呢?扒了下源碼,最終靠 懵 + 猜,發現了以下的方法:

public int c(d paramd) {
   ……
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(this.mActivity.getPackageName());
    stringBuilder.append(".wttsharesdk.WttShareActivity");
    String str = stringBuilder.toString();
    ComponentName componentName = 
    	new ComponentName(this.mActivity.getPackageName(), str);
    Intent intent = new Intent();
    intent.setComponent(componentName);
    this.mActivity.startActivity(intent);
    ……
}
複製代碼

邏輯是使用StringBuilder拼接activity路徑,而後經過ComponentName隱式啓動startActivity,回到本身的app。

至此,咱們來整理下思路,首先咱們能夠獲取到本身app棧頂activity(這個activity必須是singleTask模式),拿到ComponentName,再經過隱式Intent跳轉,不就能回到本身app任務棧了嗎?

開搞,代碼實現:

……
private String getTopClassName(){
     ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
     List<ActivityManager.RunningTaskInfo> taskInfos = manager.getRunningTasks(1);
     if (taskInfos != null && taskInfos.size() != 0){
         ComponentName componentName = taskInfos.get(0).topActivity;
         //拿到棧頂的activity className
         return componentName.getClassName();
     }
     return "";
}

private void openComponent(){
     String className = getTopClassName();
     if (!className.isEmpty()){
         ComponentName componentName = 
         	new ComponentName(getPackageName(),className);
         Intent intent = new Intent();
         intent.setComponent(componentName);
         startActivity(intent);
     }
}
……
複製代碼

在onResp()裏調用openComponent()

public void onResp(BaseResp resp) {
     if (resp.getType() == TikTokConstants.ModeType.SHARE_CONTENT_TO_TT_RESP) {
     	 ……
         openComponent();
     }
     finish();
}
複製代碼

注意棧頂activity須要設置launchMode="singleTask",至於爲何,稍後解釋

<activity
     android:name=".MainActivity"
     android:launchMode="singleTask">
</activity>
複製代碼

咱們來看看修改後的效果:

能夠看到,分享後按返回鍵正常回到了本身的app,繼續返回,退出app任務棧;接着回到抖音的任務棧,再返回,最後回到桌面,具體流程以下圖:

大概分三步:

(1)app棧頂activityB喚起抖音分享,啓動模式爲singleTask;

(2)分享結束後,抖音啓動TikTokEntryActivity,啓動模式爲singleInstance,回調onResp;

(3)TikTokEntryActivity調用finish,並經過Component啓動棧頂的activityB,因爲activityB已存在實例,系統重用該實例並調到棧頂,將任務棧拉回前臺。

總結

至此,總體看下來,主要仍是考察對activity啓動模式的理解程度,以及反編譯的一些相關知識,雖然平時接觸很少,可是當真正遇到問題的時候,咱們有了思路,纔會體現出本身肚子裏有多少墨水,從容應對。

相關文章
相關標籤/搜索