Android--搶紅包神器 輔助功能Accessibility 最新適配

新鮮出爐的搶紅包神器

前提:實(shí)現(xiàn)一個(gè)微信自動(dòng)搶紅包并不是很難,原理就是利用android的輔助功能,監(jiān)聽一下窗口變化,找到對(duì)應(yīng)控件ID,模擬點(diǎn)擊。寫好一個(gè)service服務(wù)類即可完成。但上手會(huì)發(fā)現(xiàn)這其中還是有很多問題的,所以我們主要是適配版本解決問題。

一、問題

關(guān)于搶紅包神器的文章也很多,但使用起來效果卻不佳,總結(jié)一下會(huì)有以下幾個(gè)問題 (看看是不是就是你們遇到的問題):

  • 1. 紅包來源

大多數(shù)搶紅包神器只適配了從通知欄進(jìn)入的紅包 也就是微信在后臺(tái) 此時(shí)來了紅包,監(jiān)聽通知欄,然后點(diǎn)進(jìn)去【搶】。但是事實(shí)上我認(rèn)為還需要適配兩個(gè)場景,一個(gè)是在聊天列表頁來紅包,一個(gè)是在好友會(huì)話頁面來了紅包。

  • 2. 微信版本更新,搶紅包神器紅能就不能用了

這個(gè)就是需要各個(gè)版本進(jìn)行適配 因?yàn)槲⑿琶扛掳姹荆總€(gè)控件的id會(huì)發(fā)生變化,類名有時(shí)候甚至都會(huì)混淆,改變。所以當(dāng)類名、id名稱發(fā)生改變時(shí),程序找id為null,也就沒有辦法繼續(xù)操作點(diǎn)擊,從而導(dǎo)致?lián)尲t包神器功能失效。

  • 3. 卡在【拆】的頁面不繼續(xù)

關(guān)于這個(gè)問題有以下發(fā)生的可能,第一種就是【拆】這個(gè)button的id發(fā)生了變化,第二種是手機(jī)版本大于21,在搶紅包這個(gè)頁面可能存在window嵌套,不能單單在getRootInActiveWindow 查找,需要對(duì)21前和21后的版本進(jìn)行適配。親測有效。

二、解決方案

  • 1. 紅包來源問題

若想實(shí)現(xiàn)在聊天列表頁和好友會(huì)話頁面的紅包監(jiān)聽,需要我們監(jiān)聽窗口內(nèi)容變化,也就是AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,當(dāng)監(jiān)聽到窗口內(nèi)容變化時(shí)做相應(yīng)的處理。

  • 2. 適配微信版本

本地適配,存放在一個(gè)靜態(tài) map中 key存放微信版本 value存放一個(gè)需要適配的id合集對(duì)象。然后在服務(wù)開始前判斷當(dāng)前手機(jī)安裝微信版本,然后去本地map中取出相應(yīng)的id合集。這樣使用map存儲(chǔ)版本號(hào)以及需要適配的id值來做兼容?;蚴侵苯舆m配最新的版本,用戶版本過低,提示升級(jí)。

  • 3.拆紅包

手機(jī)版本21前后做適配

三、了解android輔助功能Accessibility

AccessibilityServiceInfo
AccessibilityService
AccessibilityManager
AccessibilityEvent
Build accessibility services

AccessibilityService

AccessibilityServiceInfo

AccessibiliyEvent

AccessibilityManager

四、需要適配的對(duì)象(id名稱、class名稱等)

我們把需要適配的對(duì)象起名為WxChatTag 云控更新(構(gòu)建json)或本地靜態(tài)map存儲(chǔ)。

public static class WxChatTag implements Serializable {
        //4個(gè)Activity名字
        private String ChatListClassName;//聊天列表頁
        private String ConversationClassName;//會(huì)話頁面
        private String PopOpenRedPacketClassName;//彈出開紅包的頁面
        private String MoneyDetailClassName;//紅包領(lǐng)取詳情頁面
        //id
        private String OpenRedPacketButtonId;//拆紅包的id
        private String MoneyDetailTextId;//紅包詳情頁的錢數(shù)id
        //會(huì)話詳情頁
        private String ConversationPageListViewId;//會(huì)話頁面的listview的id
        private String ConversationPageRedPacketItemId;//會(huì)話頁面紅包View的id
        private String ConversationPageRecentMsgId;//會(huì)話頁面最新消息的id

        //聊天記錄列表頁面
        private String ChatListPageItemId;//聊天列表頁面Item的id
        private String ChatListPageRedHintId;//聊天列表頁紅色圓點(diǎn)提示view的id
        private String ChatListPageKeyTextId;//聊天列表頁新消息信息text的id

        private String KeySearchName;//會(huì)話列表頁面查找紅包的關(guān)鍵詞 領(lǐng)取紅包
//getter setter
}

關(guān)于class name名字獲取的技巧 【adb命令】

adb shell dumpsys activity | grep "mFocusedActivity" 打印棧頂當(dāng)前activity

關(guān)于id對(duì)應(yīng)情況如下圖示

MoneyDetailTextId

ConversationPageRedPacketItemId

ConversationPageListViewId

ConversationPageRecentMsgId

OpenRedPacketButtonId

ChatListPageItemId;

ChatListPageKeyTextId

ChatListPageRedHintId

五、簡易流程圖

以下為我的搶紅包神器的主要流程圖 大家作為參考。

為了適配微信版本,首先要判斷當(dāng)前用戶的微信版本和你適配的微信版本是否相同。然后進(jìn)行自定義操作。你可以本地map存儲(chǔ)取值,也可以動(dòng)態(tài)適配,網(wǎng)絡(luò)請求。

監(jiān)聽onAccessibilityEvent

監(jiān)聽通知欄

監(jiān)聽到通知欄的后續(xù)操作

監(jiān)聽到窗口變化
首先判斷當(dāng)前activity 一共有四個(gè)activity窗口需要我們做處理,其他不做處理。

監(jiān)聽窗口變化

監(jiān)聽內(nèi)容變化
這一部的主要目的就是實(shí)現(xiàn)在聊天列表頁和好友會(huì)話頁面的紅包監(jiān)聽。

監(jiān)聽內(nèi)容變化

六、主要代碼

public class MyWxQhbService extends AccessibilityService {

    /**
     * 微信的包名
     */
    public static final String PACKAGE_NAME = "com.tencent.mm";

    /**
     * 紅包消息的關(guān)鍵字
     */
    private static final String KEY = "[微信紅包]";

    private static final int APP_STATE_BACKGROUND = -1;
    private static final int APP_STATE_FOREGROUND = 1;

    private static final int WINDOW_LAUNCHER_UI = 1; // ChatListClassName
    private static final int WINDOW_LUCKY_MONEY_OPEN = 2; // PopOpenRedPacketClassName
    private static final int WINDOW_LUCKY_MONEY_DETAILUI = 3; // MoneyDetailClassName
    private static final int WINDOW_OTHER = -1;

    private static final int SILENCE_TIME = 1300;

    private int mAppState = APP_STATE_FOREGROUND;
    private int mCurrentWindow = WINDOW_OTHER;
    private boolean isSilence; // 沉默, 防止沒搶到紅包而反復(fù)點(diǎn)

    private static String ChatListClassName = "com.tencent.mm.ui.LauncherUI"; // 聊天列表頁
    private static String ConversationClassName = "com.tencent.mm.ui.LauncherUI"; //會(huì)話頁面
    private static String PopOpenRedPacketClassName = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI"; //彈出開紅包的頁面
    private static String MoneyDetailClassName = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI"; // 紅包領(lǐng)取詳情頁面


    private static String OpenRedPacketButtonId = "com.tencent.mm:id/cnu"; //  拆紅包頁面 '開'的id
    private static String MoneyDetailTextId = "com.tencent.mm:id/cnu";//紅包詳情頁 錢數(shù)id


    private static String ChatListPageItemId = "com.tencent.mm:id/azj"; // 聊天列表頁面Item的id
    private static String ChatListPageRedHintId = "com.tencent.mm:id/lu"; // 聊天列表頁紅色圓點(diǎn)提示view的id
    private static String ChatListPageKeyTextId = "com.tencent.mm:id/azn"; // 聊天記錄列表中Item關(guān)鍵詞的id

    private static String ConversationPageListViewId = "com.tencent.mm:id/ahf"; // 會(huì)話頁面的listview的id
    private static String ConversationPageRedPacketItemId = "com.tencent.mm:id/aku"; // 會(huì)話頁面紅包View的id
    private static String ConversationPageRecentMsgId = "com.tencent.mm:id/a5"; // 會(huì)話頁面最新一條信息的id

    private static String KeySearchName = "領(lǐng)取紅包";//會(huì)話頁面關(guān)鍵字搜索


    private PackageInfo mWeChatPackageInfo;
    private Intent intent = new Intent("com.wx.qhb.receiver");


    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Log.d("qhb", "onServiceConnected");

        updateConfig();
    }

    /**
     * 更新可變id、class的Config
     */
    private void updateConfig() {
        Log.d("qhb", "updateConfig");
        //獲取微信包信息
        mWeChatPackageInfo = PackageUtils.getPackageInfo(getApplicationContext(), "com.tencent.mm");
        final int versionCode = mWeChatPackageInfo.versionCode;
        Log.d("qhb", "微信:versionCode:" + versionCode);
        if (versionCode == 1360) {
            return;
        } else {
            Log.d("qhb", "versionCode>1360");
            //網(wǎng)絡(luò)請求
            ConfigHelper.getConfig(getApplicationContext(), new ConfigHelper.RequestConfigCallBack() {
                @Override
                public void onRequestFailed() {
                    Toast.makeText(getApplicationContext(), "網(wǎng)絡(luò)錯(cuò)誤,啟動(dòng)工具失敗", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onSuccess(ConfigBean.Config config) {
                    if (config != null) {
                        boolean isInit = false;
                        List<ConfigBean.WeChatVersionConfig> weChatVersionConfigs = config.getWeChatVersionConfigs();
                        for (ConfigBean.WeChatVersionConfig weChatVersionConfig : weChatVersionConfigs) {
                            if (weChatVersionConfig.getWeChatVersionCode() == versionCode) {
                                isInit = true;
                                initField(weChatVersionConfig.getWxChatTag());
                            }
                        }
                        if (!isInit) {
                            //說明沒有適配該微信版本
                            Log.d("qhb", "發(fā)送廣播");
                            sendBroadcast(intent);
                        }

                    }

                }
            });
        }


    }

    /**
     * 賦值config
     *
     * @param mWxChatTag
     */
    private void initField(ConfigBean.WxChatTag mWxChatTag) {
        Log.d("qhb", "initField");
        if (mWxChatTag == null) {
            return;
        }
        ChatListClassName = mWxChatTag.getChatListClassName();
        ConversationClassName = mWxChatTag.getConversationClassName();
        PopOpenRedPacketClassName = mWxChatTag.getPopOpenRedPacketClassName();
        MoneyDetailClassName = mWxChatTag.getMoneyDetailClassName();


        OpenRedPacketButtonId = mWxChatTag.getOpenRedPacketButtonId();
        MoneyDetailTextId = mWxChatTag.getMoneyDetailTextId();


        ChatListPageItemId = mWxChatTag.getChatListPageItemId();
        ChatListPageRedHintId = mWxChatTag.getChatListPageRedHintId();
        ChatListPageKeyTextId = mWxChatTag.getChatListPageKeyTextId();

        ConversationPageListViewId = mWxChatTag.getConversationPageListViewId();
        ConversationPageRecentMsgId = mWxChatTag.getConversationPageRecentMsgId();
        ConversationPageRedPacketItemId = mWxChatTag.getConversationPageRedPacketItemId();

        KeySearchName = mWxChatTag.getKeySearchName();
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        switch (event.getEventType()) {
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: // 通知欄狀態(tài)變化
                notificationEvent(event);
                break;
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: // 窗口狀態(tài)變化
                windowStateEvent(event);
                break;
            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:  // 窗口內(nèi)容變化
                windowContentEvent(event);
                break;
            default:
                break;
        }
    }

    /**
     * 微信是否運(yùn)行在前臺(tái)
     */
    private boolean isRunningForeground(Context context) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
        if (!tasks.isEmpty()) {
            String packageName = tasks.get(0).topActivity.getPackageName();
            if (PACKAGE_NAME.equals(packageName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 處理通知欄事件
     */
    private void notificationEvent(AccessibilityEvent event) {
        Log.d("qhb", "通知欄事件");
        if (!isRunningForeground(getApplicationContext())) {
            mAppState = APP_STATE_BACKGROUND;
        } else {
            mAppState = APP_STATE_FOREGROUND;
        }

        Parcelable data = event.getParcelableData();
        if (data == null || !(data instanceof Notification)) {
            return;
        }

        List<CharSequence> texts = event.getText();
        if (!texts.isEmpty()) {
            String text = String.valueOf(texts.get(0));
            int index = text.lastIndexOf(":");
            if (index != -1) {
                text = text.substring(index + 1);
            }
            if (text.contains(KEY)) {
//                isHasRedPacket = true;
                Notification nf = (Notification) data;
                PendingIntent pendingIntent = nf.contentIntent;
                if (NotifyUtils.isLockScreen(getApplicationContext())) {  // 是否為鎖屏或黑屏狀態(tài)
                    if (SpUtils.isLockScreenAutomaticGrab()) {
                        NotifyUtils.wakeAndUnlock(getApplicationContext());
                        NotifyUtils.send(pendingIntent); // 打開微信
                    } else {
                        NotifyUtils.showNotify(getApplicationContext(), String.valueOf(nf.tickerText), pendingIntent); // 顯示有紅包通知
                    }
                } else {
                    NotifyUtils.send(pendingIntent); // 打開微信
                }

                // 播放聲音和震動(dòng)
                NotifyUtils.playEffect(getApplicationContext());
            }
        }
    }

    /**
     * 窗口狀態(tài)變化
     */
    private void windowStateEvent(AccessibilityEvent event) {
//        Log.d("qhb", "窗口狀態(tài)變化");
        CharSequence className = event.getClassName();
        if (className == null) {
            return;
        }
        String name = className.toString();

        if (className.equals(ChatListClassName)) {
            mCurrentWindow = WINDOW_LAUNCHER_UI;
        } else if (className.equals(ConversationClassName)) {
            mCurrentWindow = WINDOW_LAUNCHER_UI;
        } else if (className.equals(PopOpenRedPacketClassName)) {
            mCurrentWindow = WINDOW_LUCKY_MONEY_OPEN;
        } else if (className.equals(MoneyDetailClassName)) {
            mCurrentWindow = WINDOW_LUCKY_MONEY_DETAILUI;
        } else {
            mCurrentWindow = WINDOW_OTHER;

        }

        switch (mCurrentWindow) {
            case WINDOW_LAUNCHER_UI:
                clickRedPackets(); // 在聊天界面, 去點(diǎn)中紅包
                break;
            case WINDOW_LUCKY_MONEY_OPEN:
                getLuckyMoney();
                break;
            case WINDOW_LUCKY_MONEY_DETAILUI:
                detailsRedPacket(); //看詳細(xì)的紀(jì)錄界面
                break;
        }


    }

    /**
     * 窗口內(nèi)容變化
     */
    private void windowContentEvent(AccessibilityEvent event) {
        Log.d("qhb", "窗口內(nèi)容變化");
        if (mCurrentWindow != WINDOW_LAUNCHER_UI) { // //不在聊天界面或聊天列表,不處理
            return;
        }

        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if (nodeInfo == null) {
            return;
        }

        // 直接去獲取當(dāng)前會(huì)話的最后一條Item, 不為null, 則是當(dāng)前會(huì)話列表
        AccessibilityNodeInfo item = AccessibilityUtils.findNodeInfosByIdLast(nodeInfo, ConversationPageRecentMsgId);
        if (item != null) {
            if (isSilence) { // 沉默中, return
                return;
            }
            clickLastMsg(nodeInfo);
            return;
        }

        // 直接去獲取聊天記錄的第一條Item, 不為null, 則是聊天記錄列表
        item = AccessibilityUtils.findNodeInfosById(nodeInfo, ChatListPageItemId); //第一條消息
        if (item != null) {
            AccessibilityNodeInfo red = AccessibilityUtils.findNodeInfosById(item, ChatListPageRedHintId);
            if (red != null) { // 有小圓點(diǎn), 說明有未讀消息
                AccessibilityNodeInfo label = AccessibilityUtils.findNodeInfosById(item, ChatListPageKeyTextId);
                if (label != null) {
                    String text = String.valueOf(label.getText());
                    Log.d("qhb", "列表頁" + label.getText());
                    int index = text.lastIndexOf(":");
                    if (index != -1) {
                        text = text.substring(index + 1);
                    }
                    if (text.contains(KEY)) {
//                        isHasRedPacket = true;
                        // 有紅包, 點(diǎn)開item
                        AccessibilityUtils.performClick(label);
                    }
                }
            }
            return;
        }
    }

    private void clickRedPackets() {

        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if (nodeInfo == null) {
            return;
        }
        //分兩種情況1.在聊天列表頁
        //2.在聊天會(huì)話頁
        //這兩個(gè)頁面的名稱都是com.tencent.mm.ui.LauncherUI這個(gè)名字
        AccessibilityNodeInfo listNode = AccessibilityUtils.findNodeInfosByTexts(nodeInfo, KEY);
        if (listNode != null) {
            Log.d("qhb", "聊天列表的微信紅包的node" + "不為空");
            AccessibilityUtils.performClick(listNode.getParent().getParent().getParent().getParent());
            return;
        } else {
            Log.d("qhb", "聊天列表的微信紅包的node" + "為空");
        }
        // 聊天會(huì)話窗口,遍歷節(jié)點(diǎn)匹配
        AccessibilityNodeInfo node = AccessibilityUtils.findNodeInfosByText(nodeInfo, KeySearchName);
        if (node != null) {
            Log.d("qhb", "會(huì)話頁領(lǐng)取紅包的node" + "不為空");
            AccessibilityUtils.performClick(node);
        } else {
            Log.d("qhb", "會(huì)話頁領(lǐng)取紅包的node" + "為空");
            return;
        }

    }


    /**
     * 點(diǎn)最新消息
     */
    private void clickLastMsg(AccessibilityNodeInfo nodeInfo) {
        AccessibilityNodeInfo listView = AccessibilityUtils.findNodeInfosById(nodeInfo, ConversationPageListViewId); //找到聊天會(huì)話頁面的會(huì)話內(nèi)容的listview
        if (listView == null) {
            return;
        }

        if (mWeChatPackageInfo.versionCode >= 1360 && listView.getChildCount() > 0) {
            listView = listView.getChild(0);
        }

        int childCount = listView.getChildCount();
        if (childCount <= 0) {
            return;
        }
        AccessibilityNodeInfo item = listView.getChild(childCount - 1);
        if (item != null) { // 每一條新消息都試著點(diǎn)紅包
            AccessibilityNodeInfo real = AccessibilityUtils.findNodeInfosById(item, ConversationPageRedPacketItemId);
            if (real != null) { // 真紅包

                // 新版本后, 1100(包括)以上, 能判斷紅包是否已經(jīng)領(lǐng)取
                if (mWeChatPackageInfo.versionCode >= 1100) {
                    AccessibilityNodeInfo realToo = AccessibilityUtils.findNodeInfosByText(real, KeySearchName);
                    if (realToo == null) {
                        return;
                    }
                }
                AccessibilityUtils.performClick(real);
            }

        }
        return;
    }

    /**
     * 搶紅包
     */
    private void getLuckyMoney() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            List<AccessibilityWindowInfo> nodeInfos = getWindows();
            for (AccessibilityWindowInfo window : nodeInfos) {
                AccessibilityNodeInfo nodeInfo = window.getRoot();
                if (nodeInfo == null) {
                    break;
                }
                List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(OpenRedPacketButtonId);
                if (list != null && list.size() > 0) {
                    AccessibilityUtils.performOpenRedPacketWithDelay(list.get(0));
                    return;
                }
            }
        }

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
            AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();  //獲得整個(gè)窗口對(duì)象
            if (nodeInfo == null) {
                return;
            }

            List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(OpenRedPacketButtonId);
            if (list != null && list.size() > 0) {
                AccessibilityUtils.performOpenRedPacketWithDelay(list.get(0));
                return;
            }

            //如果沒找到拆紅包的button,則將界面上所有子節(jié)點(diǎn)都點(diǎn)擊一次
            for (int i = nodeInfo.getChildCount() - 1; i >= 0; i--) {
                if (("android.widget.Button").equals(nodeInfo.getChild(i).getClassName())) {
                    AccessibilityUtils.performOpenRedPacketWithDelay(nodeInfo.getChild(i));
                    return;
                }
            }
//            Toast.makeText(this, "未找到開紅包按鈕", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 領(lǐng)取詳情
     */
    private void detailsRedPacket() {
        // 到這, 領(lǐng)取流程算是完了
        Log.d("qhb", "領(lǐng)取流程完事");

        List<AccessibilityNodeInfo> moneyNode = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(MoneyDetailTextId);
        if (moneyNode != null && moneyNode.size() > 0) {
            String moneyStr = moneyNode.get(0).getText().toString();
            float money = Float.parseFloat(moneyStr);
            SpUtils.put("totalNum", SpUtils.get("totalNum", 0) + 1);
            SpUtils.put("totalMoney", SpUtils.get("totalMoney", 0f) + money);
        }
        back();

    }

    /**
     * 返回
     */
    private void back() {
        back(-1);
    }

    /**
     * 返回
     */
    private void back(int count) {
        Log.d("qhb", "back:" + count);
        silence(); // 沉默

        int backCount;
        if (mAppState == APP_STATE_BACKGROUND) {
            mAppState = APP_STATE_FOREGROUND;
            backCount = 3;
        } else {
            backCount = 1;
        }

        if (count != -1) {
            backCount = count;
        }

        for (int i = 0; i < backCount; i++) {
            AccessibilityUtils.performBack(this);
            if (i < backCount - 1) {
                SystemClock.sleep(666);// 需要個(gè)時(shí)間差
            }
        }
    }

    /**
     * 沉默
     */
    private void silence() {
        isSilence = true; // 開啟沉默
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                isSilence = false;
            }
        }, SILENCE_TIME);
    }


    @Override
    public void onInterrupt() {
        Log.d("qhb", "onInterrupt 搶紅包服務(wù)中斷");
    }

}

七、效果圖

開啟.gif
通知欄的紅包.gif
聊天列表頁來了紅包.gif

會(huì)話頁的紅包.gif

八、apk體驗(yàn)鏈接

apk體驗(yàn)鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 生命其實(shí)很短,只有兩天 一天用來出生,而一天用來死亡 它們相遇的一刻,也就有了生死存亡 只是生命一開始,就有了區(qū)別...
    周延龍閱讀 307評(píng)論 0 1
  • 01 孔子曰:吾十有五而志于學(xué)。15歲,這個(gè)年齡節(jié)點(diǎn)很有意思,按照當(dāng)前的教育階段,是一個(gè)孩子從初中畢業(yè)進(jìn)入高中之際...
    04b12f4ce9fd閱讀 676評(píng)論 0 2

友情鏈接更多精彩內(nèi)容