抖音爬蟲教程,AndServer+Service 打造 Android 服務器實現 so 文件調用

so 文件調用

隨着 Android 移動安全的高速發展,不論是爲了執行效率仍是程序的安全性等,關鍵代碼下沉 native 層已成爲基本操做。<br>native 層的開發就是通指的 JNI/NDK 開發,經過 JNI 能夠實現 java 層和 native 層(主要是 C/C++ )的相互調用,native 層經編譯後產生 so 動態連接庫,so 文件具備可移植性廣,執行效率高,保密性強等優勢。<br>那麼問題來了,如何調用 so 文件顯得異常重要,固然你也能夠直接分析 so 文件的僞代碼,利用強悍的編程功底直接模擬關鍵操做,可是我想對於普通人來講頭髮仍是比較重要的。 <br>當前調用 so 文件的主流操做應該是: <br>1,基於 Unicorn 的各類實現(還在學習中,暫且不表)  <br>2,Android 服務器的搭建,在 App 內起 http 服務完成調用 so 的需求(固然前提是過了 so 的效驗等操做)<br>至於爲何選用 AndServer,好吧,不爲何,只是由於搜索到了它  <br>爲何結合 Service,在學習 Android 開發的時候瞭解到了 Service 的生命週期,我的理解用 Service 去建立 Http 服務比較好。 <br>固然也有 Application 的簡單使用,由於在正式環境中,大多數 so 文件的邏輯中都有 context 的一些包名了,簽名了的效驗等,自定義 Application 的話獲取 context 傳參就行了。java

libyemu.so 簡介

這是我編譯好的一個 so 文件,就是根據入參作下簡單的字符串拼接(如下是 native 層編譯前的 c 代碼)android

extern "C"
JNIEXPORT jstring JNICALL
Java_com_fw_myapplication_ndktest_NdkTest_stringFromUTF(JNIEnv *env, jobject instance, jstring str_) {
    jclass String_clazz = env->FindClass("java/lang/String");
    jmethodID concat_methodID = env->GetMethodID(String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring str = env->NewStringUTF("  from so --[NightTeam夜幕]");
    jobject str1 = env->CallObjectMethod(str_, concat_methodID, str);
    const char *chars = env->GetStringUTFChars((jstring)str1, 0);
    return env->NewStringUTF(chars);
}

這部分代碼仍是有必要貼一下的,簡單的靜態註冊使用了反射的思想,反射在逆向中相當重要<br>接下來是 java 代碼,定義了 native 函數編程

package com.fw.myapplication.ndktest;
public class NdkTest {
    public static native String stringFromUTF(String str);
    static {
        System.loadLibrary("yemu");
    }
}

若是到這裏有點懵逼的同窗可能須要去補下 Android 開發基礎了json

Android 項目測試 so

先說下個人環境,由於這個環境影響太大了  <br>1,AndroidStudio 3.4  <br>2,手機 Android 6 架構 armeabi-v7a  <br>打開 AndroidStudio 新建 project  <br><br>在 module 的 build 中加這麼一句,而後 sync  <br><br>把編譯好的 so 文件複製到 libs 文件夾下(和剛纔的 jniLibs.srcDirs 對應)  <br><br>把 so 對應的 java 代碼也 copy 過來,注意包名類名的一致性  <br><br>打開 activity_main.xml 文件爲 TextView 添加 id  <br><br>打開 MainActiviy.java 開始編碼  <br><br>這兩行的意思就是,先從佈局中找到對應 id 的 TextView,而後爲其設置 Text(調用 native 函數的返回值)  <br>下面測試一下我們的 so 調用狀況  <br><br>能夠看到我們的 so 文件調用成功(這裏我們的 so 沒有效驗,只是測試 app 是否能夠正常調用)<br>瀏覽器

AndServer 代碼編寫

AndServer 官方文檔:https://yanzhenjie.com/AndServer/  <br>打開官方文檔,看看人家的入門介紹,新建 java 文件  <br><br>如圖經典 MVC 的 C 就寫好了,定義了一個 nightteam_sign 接口,請求方式爲 get,請求參數爲 sign,調用 native 函數,而後返回 json,可是這裏我想利用 Application 獲取下 context 對象,取下包名,接下來自定義 Applictaion<br>安全

package com.nightteam.httpso;
import android.app.Application;
public class MyApp extends Application {
    private static MyApp myApp;
    public static MyApp getInstance() {
        return myApp;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        myApp = this;
    }
}

而後在 manifest 文件中指定要啓動的 Application  <br><br>而後修改 MyController.java 的代碼  <br><br>接下來把官方文檔-服務器的代碼 copy 下來  <br>導入一些包,修改部分代碼以下  <br><br>新版本的 AndServer.serverBuilder 已經須要傳遞 context 了,這裏把網絡地址和端口號也修改成從構造參數中獲取,到這裏 AndServer 的東西基本完了,實際上我們就搭建一個調 so 的接口,並無過多的業務邏輯,因此代碼就是使用的最簡單的<br>服務器

Service 代碼編寫

我們這裏用按鈕的點擊事件啓動 Service,故在 activity_main.xml 中添加一個 button 並指定點擊事件  <br><br><br>接下來編寫自定義 Service 代碼<br>網絡

package com.nightteam.httpso.Service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.nightteam.httpso.ServerManager;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class MyService extends Service {
    private static final String TAG = "NigthTeam";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: MyService");
        new Thread() {
            @Override
            public void run() {
                super.run();
                InetAddress inetAddress = null;
                try {
                    inetAddress = InetAddress.getByName("0.0.0.0");
                    Log.d(TAG, "onCreate: " + inetAddress.getHostAddress());
                    ServerManager serverManager = new ServerManager(getApplicationContext(), inetAddress, 8005);
                    serverManager.startServer();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

打上了幾個 log,在子線程中啓動 AndServer 的服務(什麼時候使用 UI 線程和子線程是 Android 基礎,這裏就不贅述了)  <br>注意一下,這裏從 0.0.0.0 獲取 inetAddress,可不要寫錯了,localhost 和 0.0.0.0 的區別請移步搜索引擎  <br>而後就是向 ServerManager 的構造函數傳遞 context,inetAddress,port 用來 new 對象,隨後開啓服務<br>最後注意檢查下 manifest 文件中 Service 的聲明  <br>架構

開啓 Service,並獲取本機 ip

回到咱們的 MainActivity.java 的 operate( button 的點擊事件)編寫啓動 Service 代碼app

public void operate(View view) {
        switch (view.getId()){
            case R.id.id_bt_index:
                //啓動服務:建立-->啓動-->銷燬
                //若是服務已經建立了,後續重複啓動,操做的都是同一個服務,不會再從新建立了,除非你先銷燬它
                Intent it1 = new Intent(this, MyService.class);
                Log.d(TAG, "operate: button");
                startService(it1);
                ((Button) view).setText("服務已開啓");
                break;
        }
    }

到這裏咱們的服務基本搭建好了,可是爲了方便起見,我想把我們的本機 ip 顯示在 App 上,這樣咱們就不用去設置再查看了  <br>我在網上找到了一個獲取 ip 地址的一個工具類,源碼以下:

package com.nightteam.httpso;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.regex.Pattern;
public class NetUtils {
    private static final Pattern IPV4_PATTERN = Pattern.compile("^(" +
            "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
            "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
    private static boolean isIPv4Address(String input) {
        return IPV4_PATTERN.matcher(input).matches();
    }
    //獲取本機IP地址
    public static InetAddress getLocalIPAddress() {
        Enumeration<NetworkInterface> enumeration = null;
        try {
            enumeration = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                NetworkInterface nif = enumeration.nextElement();
                Enumeration<InetAddress> inetAddresses = nif.getInetAddresses();
                if (inetAddresses != null)
                    while (inetAddresses.hasMoreElements()) {
                        InetAddress inetAddress = inetAddresses.nextElement();
                        if (!inetAddress.isLoopbackAddress() && isIPv4Address(inetAddress.getHostAddress())) {
                            return inetAddress;
                        }
                    }
            }
        }
        return null;
    }
}

把工具類 copy 到咱們的 Android 項目中,繼續在 MainActivity.java 中編碼  <br><br>獲取了一下本機地址和 Android SDK 版本( Android 8 以後啓動 Service 方式不同)<br>

申請權限,啓動 App

最後一步就是爲 app 申請網絡權限了  <br><br>隨後鏈接咱們的手機,運行項目,測試一下,點擊開啓服務  <br><br>看下 AndroidStudio 日誌  <br><br>好像一切正常,在瀏覽器訪問下試試( ip 就是 App 中顯示的 ip 地址)  <br><br>如圖正常訪問到了咱們想要的內容<br>回過頭來講下 Service,打開咱們手機的設置,找到應用程序管理-運行中的服務(手機不一樣,方式不一樣)<br><br>能夠看到咱們的程序,運行了一個服務,這個服務就是我們編碼的 MyService<br><br>接下來殺掉該 App進程,再次查看運行中的服務<br><br>我這裏在權限管理設置了自動運行,能夠保持服務的運行。(這個地方仍是根據系統有大小差別)<br>至此使用 App 起 http 服務調 so 就完成了

TiToData:專業的短視頻、直播數據接口服務平臺。 更多信息請聯繫: TiToData 覆蓋主流平臺:抖音,快手,小紅書,TikTok,YouTube

相關文章
相關標籤/搜索