leaderboard 排行榜 category 分类浏览 code 独立开发者 notifications 通知中心 download 下载 App
person

登录 AppShare

默认使用账号密码登录,也可以切换邮箱验证码。

还没有账号?

person_add

注册 AppShare

创建账号后即可参与版本讨论和收藏提醒。

已有账号?

轻悦时光

轻悦时光

正式版
category 图书阅读 / 小说 update 2.1.0711 (2173) storage 73.63MB
15 下载
0 讨论
2 收藏

new_releases 更新日志

轻悦时光 0711 修复切换引擎后背景音乐没有开启需要再次手动开启 搜索tabs新增记忆 允许每本书设置单独朗读引擎(需要在阅读设置中关闭全局一致) 修改字间距范围 允许关闭阅读时间的记录 新增清除阅读统计 新增发现筛选函数 修复从webdav 恢复书本时进度条不显示 重新设计缓存结构,旧缓存会失效,下载管理新增已缓存(进入清除缓存界面时如果有旧版本缓存会弹窗提示清理) 原生ios26 底栏选择底栏跟随主题 听书定时新增自动开启功能,打开开关时每次听书时都会自动开启定时关闭 云端书架 排版 书签新增删除按钮 将flutter_svg 同步至最新版来支持百分比svg图片 修复点击全选本段后再点击高亮 高亮的还是之前的 适配新的xh订阅源 新增云端书源 朗读优化允许在鸿蒙段使用(打开后在进度还剩20毫秒时就跳过,部分觉得段落之间有停顿的可以打开) 切换书源新增加载目录 统一字数字段格式(会自动格式化为**万字)

description 应用介绍

轻悦时光 一款多平台可用的阅读软件,通过 webview 来运行书源以达到多平台兼容的效果。 交流群 qq交流群:519620220 书本简介说明 书本简介支持html ,如果需要使用html,请在最前面添加:@html: ,例如:@html: <p>这是一个段落</p> 。 如果不加@html:前缀则会直接显示为文本。 正文文本说明 正文文本不支持除了img 以外的标签, 图片可以使用img标签例如 <img src="****"> img 标签里的src 支持header 如果需要修改header可以这么设置,http://127.0.0.1,{'headers':{'a':'b'}} ,当然这种写法不仅仅支持这也支持封面 正文图片解析说明 和文字同行的图片会默认识别为段评,小图显示,其他图片会正常显示。 例如 轻悦时光是最好用的阅读器<img src="a" />,支持多平台<img src="b" />。\r\n <img src="c" /> 上面ab 两个图片会以段评显示,c正常显示。 如果想点击支持js请这么写: <img src="b,{'js':'要运行的js'}"/> img src 必须用双引号包裹,所以后面的json只能用单引号。 关于图片是支持base64图片的,但如果base64里是svg图片请勿使用%,fluttersvg不支持百分比,轻阅读是用后端转码了,轻悦时光不支持带百分比的svg。 图片后面的json说明 图片后面可以接一个json ,目前支持以下几个参数: js:要运行的js,只能在书源代码中使用,在阅读器中携带js的图片是可以直接点击运行的 headers:访问图片时携带的headers,例如{'headers':{'a':'b'}} imageDecode:是否需要解密图片,默认是false,如果需要解密图片需要在书源中实现解密函数 段评图片使用 如果要使用应用自带的段评图片,请按照如下写法 例如: <img src="dp:1,{'js':'要运行的js'}" /> 1 为段评数量 js加密解密 如果你的代码涉及到加密解密可以引用下面的js <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script> 通用 js 通用 js 的函数分前台 webview 可用和源可用,源可用的话只能在书源代码中使用,前台 webview 可用那表示能在登录或者你启动的前台 webview 中使用, 未单独说明的是两种情况下都能用 <!-- 没用到jq请去掉--> <script src="https://vc.jd.com/web/js/jquery-3.1.1.min.js"></script> <script> var isCookieJar=true;// 不需要CookieJar请修改此处 class FlutterJSBridge { constructor() { this.init(); //前台webview 里必须删除这行 } init() { if (window.flutter_inappwebview) { this.isReady = true; this.CookieJar(); } else { window.addEventListener('flutterInAppWebViewPlatformReady', () => { this.isReady = true; console.log('JSBridge初始化完成'); this.CookieJar(); }); } } //通知原生页面初始化完成,仅在书源和tts生效,webview请勿使用,只有通知加载成功后才允许运行,否则会一直等待加载成功 async CookieJar() { try { await window.flutter_inappwebview.callHandler('CookieJar', isCookieJar); } catch (error) { console.error('汇报完成准备失败:', error); } } //获取应用编译版本 async getbuildNumber() { try { return await window.flutter_inappwebview.callHandler('buildNumber'); } catch (error) { return 0; } } //获取应用版本 async getversion() { try { return await window.flutter_inappwebview.callHandler('version'); } catch (error) { return "0.0.0"; } } //将简体字转成繁体字 async toTraditional(str) { try { return await window.flutter_inappwebview.callHandler('toTraditional',str); } catch (error) { return ""; } } //将繁体字转成简体字 async toSimplified(str) { try { return await window.flutter_inappwebview.callHandler('toSimplified',str); } catch (error) { return ""; } } //获取设备唯一id async getDeviceid() { try { return await window.flutter_inappwebview.callHandler('id'); } catch (error) { return ""; } } //获取设备平台 此处返回 windows、macos、ios、ohos、android async getDevice() { try { return await window.flutter_inappwebview.callHandler('device'); } catch (error) { return ""; } } //输出日志,前台webview请勿使用 //str 为 String async log(str) { try { return await window.flutter_inappwebview.callHandler('log',str); } catch (error) { return false; } } //书源调试时可输出 html 代码到前台 //type 0 搜索源码 , 1详情源码 ,2目录源码 ,3正文源码 //str 为 String //type 为int async text(type,str) { try { return await window.flutter_inappwebview.callHandler('text',type,str); } catch (error) { return false; } } //toast弹窗 //str 为 String async showToast(str) { try { return await window.flutter_inappwebview.callHandler('showToast',str); } catch (error) { return false; } } //webview 里禁止使用,webview请使用js获取ua (navigator.userAgent) //获取默认ua async getWebViewUA() { try { return await window.flutter_inappwebview.callHandler('getWebViewUA'); } catch (error) { return ""; } } //通过url打开外部应用 //url 为 String async openurl(url) { try { return await window.flutter_inappwebview.callHandler('openurl',url,""); } catch (error) { return false; } } //通过url打开外部应用并附带mimeType //url 为 String //mimeType 为 String async openurlwithMimeType(url,mimeType) { try { return await window.flutter_inappwebview.callHandler('openurl',url,mimeType); } catch (error) { return false; } } /** * 使用webView访问网络 * @param html 直接用webView载入的html, 如果html为空直接访问url * @param url html内如果有相对路径的资源不传入url访问不了 * @param js 用来取返回值的js语句, 没有就返回整个源代码 * @param body 当参数不为空的时候,会以post请求,此时请务必在 header 中带上content-type * @param header 请求的header头,此参数必须是json字符串 * @return 返回js获取的内容 */ async webview(url,js,html,body,header) { try { return await window.flutter_inappwebview.callHandler('webview',url,js,html,body,header,"",""); } catch (error) { return ""; } } /** * overrideUrlRegex 为正则表达式 * 使用方法和上面的一样 * 但返回的内容为正则到的内容,如果无法正则到则返回 js 获取的内容,如果 js 为空则返回页面 html */ async webViewGetOverrideUrl(url,js,html,body,header,overrideUrlRegex) { try { return await window.flutter_inappwebview.callHandler('webview',url,js,html,body,header,overrideUrlRegex,""); } catch (error) { return ""; } } /** * 使用webView获取资源url * urlregex 为正则表达式 * 使用方法和上面的一样 * 但返回的内容为正则到的内容,如果无法正则到则返回 js 获取的内容,如果 js 为空则返回页面 html */ async webViewGetSource(url,js,html,body,header,urlregex) { try { return await window.flutter_inappwebview.callHandler('webview',url,js,html,body,header,"",urlregex); } catch (error) { return ""; } } /** * 启动前台 webview 访问链接并获取结束时的 html,可用于手工过盾 * @param url 网址 * @param title 标题 * @param header 请求的header头,此参数必须是json字符串 * @return 返回网页的内容 */ async startBrowser(url,title,header) { try { return await window.flutter_inappwebview.callHandler('startBrowser',url,title,header); } catch (error) { return ""; } } /** * 启动前台 webview 并对每次打开的 url 进行拦截 * @param url 网址 * @param title 标题 * @param header 请求的header头,此参数必须是json字符串 */ async startBrowserWithShouldOverrideUrlLoading(url,title,header) { try { return await window.flutter_inappwebview.callHandler('startBrowserWithShouldOverrideUrlLoading',url,title,header); } catch (error) { return ""; } } //专门为段评设置的半屏显示,不返回任何东西 async startBrowserDp(url,title) { try { return await window.flutter_inappwebview.callHandler('startBrowserDp',url,title); } catch (error) { return ""; } } //仅前台webview可以使用,返回按钮,返回上一个页面 async back() { try { return await window.flutter_inappwebview.callHandler('back'); } catch (error) { return false; } } //将 utf8字符串转到 gbk 并 url 编码 async utf8ToGbkUrlEncoded(str) { try { return await window.flutter_inappwebview.callHandler('utf8ToGbkUrlEncoded',str); } catch (error) { return ""; } } /* * @param str为图片链接 * @param header 请求的header头,此参数必须是json字符串 * 此函数是让用户输入图片中的验证码,当链接为空则直接让用户输入验证码 */ async getVerificationCode(str,header) { try { return await window.flutter_inappwebview.callHandler('getVerificationCode',str,header); } catch (error) { return ""; } } //提交内容bookUrl,我会调用书源 info 函数来获取这本书的信息 async addbook(bookUrl) { try { return await window.flutter_inappwebview.callHandler('addbook',bookUrl); } catch (error) { return ""; } } //utf8 字符串转base64 async base64encode(str) { try { return await window.flutter_inappwebview.callHandler('base64encode',str); } catch (error) { return ""; } } //base64 转utf8字符串 async base64decode(str) { try { return await window.flutter_inappwebview.callHandler('base64decode',str); } catch (error) { return ""; } } } //webview下isCookieJar必定true 会自动处理cookie //以下提交的url,headers,body 都必须为字符串,headers必须为json字符串 //当followRedirects 为 false 时不处理重定向,当为 true 时会自动处理重定向 ,如不明白用途直接用 true 最佳 // 以下所有参数除当followRedirects外均为 String // 如果需要使用http2协议 请在url 前添加 http2:// ,例如 http2://baidu.com // 如果https一直被盾拦截 ,可以使用https2协议 class Http { constructor() {} /* * 通用返回字段 * method post get 或者 head * body 请求返回后的字节的 base64 * headers map<String,List<String>> 可通过headers[""]来或者 * statusCode 状态码 * statusMessage * data 返回后的字节 格式化后的内容 */ async Get(url,headers,followRedirects) { try { return await window.flutter_inappwebview.callHandler('http',"get",url,"",JSON.stringify(headers),followRedirects,""); } catch (error) { return null; } } async Head(url,headers,followRedirects) { try { return await window.flutter_inappwebview.callHandler('http',"head",url,"",JSON.stringify(headers),followRedirects,""); } catch (error) { return null; } } async Post(url,headers,body,contenttype,followRedirects) { try { return await window.flutter_inappwebview.callHandler('http',"post",url,body,JSON.stringify(headers),followRedirects,contenttype); } catch (error) { return null; } } } class Cache { constructor() {} async get(key) { try { return await window.flutter_inappwebview.callHandler('cache.get',key); } catch (error) { return null; } } async set(key,value) { try { return await window.flutter_inappwebview.callHandler('cache.set',key,value); } catch (error) { return null; } } async remove(key) { try { return await window.flutter_inappwebview.callHandler('cache.remove',key); } catch (error) { return null; } } //如果登录为弹窗格式的,里面输入框输入的内容可以通过这个函数获取,默认返回的json格式或者为空,需要自行转换 async getLoginInfo(){ return await this.get("LoginInfo") } //将修改后的弹窗输入内容报错 ,必须 JSON.stringify,不然会出错 async putLoginInfo(info){ return await this.set("LoginInfo",info) } //获取书本变量 async getbookVariable(bookurl){ return await this.get(bookurl) } //写入书本变量 async setbookVariable(bookurl,value){ return await this.set(bookurl,value) } } class Cookie { constructor() {} //通过url获取当前url的所有cookie async get(url) { try { return await window.flutter_inappwebview.callHandler('cookie.get',url); } catch (error) { return null; } } //通过url删除当前url的所有cookie async remove(url) { try { return await window.flutter_inappwebview.callHandler('cookie.remove',url); } catch (error) { return null; } } //通过url保存当前url的所有cookie async set(url,value) { try { return await window.flutter_inappwebview.callHandler('cookie.set',url,value); } catch (error) { return null; } } //设置单独一个cookie async setCookie(url,key,value) { try { return await window.flutter_inappwebview.callHandler('cookie.setcookie',url,key,value); } catch (error) { return null; } } //通过 url 获取单个 cookie 的值 async getCookie(url,value) { try { return await window.flutter_inappwebview.callHandler('cookie.getCookie',url,value); } catch (error) { return null; } } } //安全的创建一个 div 解析 html function parseHTMLSafely(htmlStr) { try { // 在函数作用域内创建独立的临时容器 // 每个调用创建新的jQuery对象,互不影响 var tempDiv = document.createElement('div'); tempDiv.innerHTML = htmlStr; return $(tempDiv); } catch (e) { flutterBridge.log("HTML解析错误:"+e.message); return $('<div>'); } } //parseHTMLSafely 创建的用完后必须删除 function removeHTMLSafely(tempContainer) { try { tempContainer.innerHTML = ''; if (tempContainer.parentNode) { tempContainer.parentNode.removeChild(tempContainer); } } catch (e) { flutterBridge.log("HTML移除失败:"+e.message); } } //移除 css js,创建parseHTMLSafely前如果用不上 cssjs 建议移除 function removeHTMLTags(htmlString) { // 移除script标签 let result = htmlString.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, ''); // 移除style标签 result = result.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, ''); return result; } </script> 书本类 { "bookUrl":"", //书本 url 不可重复 "name":"", //书本名称 "author":"", //作者 "kind":"", //分类 "coverUrl":"", //封面 "intro":"", //简介 "tocUrl":"", //目录 url "wordCount":"", //字数 "type":"", //书本类别 0 小说 1 听书 2 漫画 "latestChapterTitle":"", } 目录类 { "name" :"", //章节标题 "chapterId":"", //正文 url "index" :0, //index "isPay":false, //是否需要付费 "isVip":false, //是否是 vip "isVolume":false, //是否是卷名 "tag":"" //小标题 }; 当isvip 为 true ispay 为false时会显示购买按钮 发现类 { "title" :"", //标题 "url":"", //url "js":"", //要运行的 js "type" :0, "width": 0, }; url 和 js 只能填一个 当type为 0 正常解析发现页,当 type 为 1 则会用 webview 打开 url, width 为 0 时则默认处理宽度(1行3个), 1 是一行2个 ,3 是一行1个 url 和 js 都为空是会按照 width = 3处理 登录类 { "name" :"", //标题 "action":"", //执行的js 仅button生效 "type" :"", //button text password }; 当type为 0 正常解析发现页,当 type 为 1 则会用 webview 打开 url 书源 搜索函数 //如果没有分页 请在 page 为 2 及以上返回 "[]" //当前函数返回书本数组的 json async function search(key,page) { } 详情页函数 //当前函数返回书本的 json async function info(bookurl) { } 目录页函数 //当前函数返回目录数组的 json async function chapter(tocUrl) { } 正文页函数 //提交内容为目录类里的chapterId //当前函数返回字符串 async function content(url) { } 发现函数 //当前函数返回发现数组的 json async function getfinds() { } 发现搜索函数 //如果没有分页 请在 page 为 2 及以上返回 "[]" //当前函数返回书本数组的 json async function find(url,page) { } 购买函数 //提交内容bookurl为书本url,url为目录的chapterId // 执行完成后会刷新目录和正文 async function pay(bookurl,url) { } 登录函数 //返回http开头的url 或者 登录数组的json //如果是登录数组的json 用户登录完会执行 await login() async function getloginurl() { } async function login(){ } 图片解密函数 // url 为图片的url,如果需要传递参数可以在图片后接json字符串,例如:http://127.0.0.1,{'headers':{'a':'b'}} //图片解密,image 为加密的图片的base64,执行的js必须是字符串所以这参数只能base64转码 //这个函数得返回byteList List<int> ,并且能直接被Uint8List.fromList(byteList)接受 async function imagedecrypt(url,image){ } webview 拦截函数 // 当调用startBrowserWithShouldOverrideUrlLoading时必须有此函数 // url 为每次打开的 url // 返回 false 则会取消打开这个网页 async function shouldOverrideUrlLoading(url){ return true; }