美文网首页
阅读时间

阅读时间

作者: 我在等你回复可你没回 | 来源:发表于2019-04-22 02:48 被阅读0次

    1.在数据库WRReader中的,userInfo表中


    image.png

    2.下面这个函数去设置时间


    image.png

    3.界面上显示“可兑XX书币“
    XX的值来自于下面com.tencent.weread.home.fragment.PersonalController类的函数。可以看到参数userInfo的getCanExchange函数就是用来获取可以兑换多少书币的。这个UserInfo第一次初始化肯定是访问服务器取得的。单单修改这里肯定不可行,会被服务器的值覆盖掉的。因为Hook点不再这里,需要Hook住计算时间的算法。

        private void renderUserInfo(UserInfo userInfo) {
            this.mPersonalView.renderSignature(userInfo.getSignature());
            this.mPersonalView.renderBookInfo(userInfo.getBuyCount());
            this.mPersonalView.renderMyReviewAccessory(userInfo.getNoteBookCount(), userInfo.getReviewLikedCount(), userInfo.getReviewCommentedCount());
            this.mPersonalView.renderFollowAccessory(userInfo.getFollowerCount(), userInfo.getFollowingCount(), userInfo.getWechatFriendCount());
            this.mPersonalView.renderBookInventoryAccessory(userInfo.getBooklistCount() + userInfo.getBooklistCollectCount(), userInfo.getBooklistCollectCount());
            this.mPersonalView.renderArticleAccessory(!ai.isNullOrEmpty(userInfo.getArticleBookId()), userInfo.getArticleCount(), userInfo.getArticleReadCount(), userInfo.getArticleWordCount());
            this.mCanExchange = userInfo.getCanExchange();
            if (this.mFriendRank != null) {
                this.mPersonalView.renderRankAndExchange(this.mFriendRank, this.mCanExchange);
            }
        }
    

    我们可以hook住这个函数,强制执行setCanExchange,可以更改界面的显示。但这个只是能更改显示,并不是修改最终值。

            Class<?> userInfoClass = XposedHelpers.findClass("com.tencent.weread.model.domain.UserInfo", classLoader);
            if (userInfoClass != null) {
                XposedBridge.log("wenfengtou load class " + userInfoClass.toString());
                Log.i(TAG,"wenfengtou load class " + userInfoClass.toString());
            }
            XposedHelpers.findAndHookMethod("com.tencent.weread.home.fragment.PersonalController", lpparam.classLoader, "renderUserInfo", userInfoClass, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Object userInfoObj = param.args[0];
                    Log.i(TAG, "before renderUserInfo");
                    XposedHelpers.callMethod(userInfoObj, "setCanExchange", 400);
                    Log.i(TAG, "userInfoObj = " +  userInfoObj);
                }
            });
    

    我们要继续追溯这个UserInfo是怎么来的。可以看到是通过一个Cache的clone方法来的。

        public void convertFrom(Cursor cursor) {
            String[] columnNames = cursor.getColumnNames();
    (!Cache.from(abstractCursor.getDatabase()).getCache(UserInfo.class).clone(abstractCursor, this, null)) {
    
        }
    

    查看UserInfo函数,发现是通过convertFrom函数来的。所以这些原始的数据


    image.png

    但是发现根本没有调用到这个函数,天!

    只能通过trace看看UserInfo哪里有调用了,囧


    image.png

    看上去是通过Rxjava这里返回了结果


    image.png

    所以要看下UserInfo数据表是怎么建立起来的?
    UserInfo表是数据库WRReader中。
    通过跟踪Trace,
    UserInfo.createTable
    WRReader.onCreate
    WRBookSQLiteHelper.onCreate
    WRBookSQLiteHelper.onCreate
    com.tencent.moai.database.sqlite.SQLiteOpenHelper.getDatabaseLocked
    com.tencent.moai.database.sqlite.SQLiteOpenHelper.getReadableDatabase

    找到Rxjava调用onNext的入口


    image.png

    今日实验步骤:
    确定数据库的时间什么时候写入的?


    image.png

    听音频这个时间是不会变的

    看书的话会变


    image.png

    通过实验发现,是在开始阅读的时候写入的数据库。所以应该是都会从服务器获取数据。所以hook的点应该要在上传数据的时候或者时间计算的算法。

    image.png image.png image.png image.png

    那么我们是不是可以修改这个加速的值来实现加速呢?答案是肯定的!!
    ProgressReportStrategy.java

                int acceleration = ((int) (this.readingTime / 1000)) * ((ReadingTimeAcceleration) Features.of(ReadingTimeAcceleration.class)).acceleration();
    

    他是通过feature来控制的。

    package moai.feature;
    
    import com.tencent.weread.book.feature.Accelerate1;
    import com.tencent.weread.book.feature.Accelerate10;
    import com.tencent.weread.book.feature.Accelerate100;
    import com.tencent.weread.book.feature.ReadingTimeAcceleration;
    import moai.feature.wrapper.IntFeatureWrapper;
    
    public final class ReadingTimeAccelerationWrapper extends IntFeatureWrapper<ReadingTimeAcceleration> {
        public ReadingTimeAccelerationWrapper(FeatureStorage featureStorage, Class cls) {
            super(featureStorage, "reading_time_acceleration", Integer.valueOf(1), cls, 3, "阅读时间加速", Groups.FEATURE);
        }
    
        /* Access modifiers changed, original: protected|final */
        public final void initializeIndex() {
            mapIndex(Integer.valueOf(10), 0, Accelerate10.class);
            mapIndex(Integer.valueOf(1), 1, Accelerate1.class);
            mapIndex(Integer.valueOf(100), 2, Accelerate100.class);
        }
    }
    

    直接修改发现有报错

    05-01 07:49:09.341  2769  2769 I HookMain: after calculateReadingTime10870685
    05-01 07:49:09.341  2769  2769 I HookMain: before WRLog logProgressReportStrategy saveLastReadAndReport page:421 mode:NORMAL
    05-01 07:49:09.345  2769  2769 I HookMain: before WRLog logProgressReportStrategy ProgressReport pageNumber[421], totalPage[427]
    05-01 07:49:09.345  2769  2769 I HookMain: after acceleration
    05-01 07:49:09.365  2769  3045 I HookMain: before WRLog logReadingProgressReporter report called. bookId:840704,chapterUid:52,reviewId:,htmlPos:384,progress:99,deltaTime:11470,source:0,enableProgress:false,summary:9
    05-01 07:49:09.366  2769  3045 I HookMain: before WRLog logReadingProgressReporter report called cancel, because deltaTime too large.
    

    上传取消了。

    联网传送的话,可能服务器有验证。因此尝试断网的控制
    可以看到有下面的log。

    05-01 13:25:11.699 15559 15745 I HookMain: before WRLog logReportService resendOfflineReadingInfos success
    05-01 13:25:11.699 15559 15745 I HookMain: before WRLog logReportService resendOfflineReadingInfos success
    

    相关文章

      网友评论

          本文标题:阅读时间

          本文链接:https://www.haomeiwen.com/subject/pxgkgqtx.html