「 daza.io 」是一款基于技能树(正在实现)的技术内容聚合应用,根据你的技能对内容进行筛选,让你在这个信息过载的时代里更高效地获取你所需的内容。
自上次发文章之后已经过了 2 个月了,我也在 11 月 19 号结束了一个人的旅行(历时 59 天)回到了深圳,专心于完成这个全端项目的客户端开发,终于在 12 月 2 号 iOS 版上线 AppStore , 12 月 7 号 Android 上线到 GooglePlay 。
最初我将 iOS 版定价为 1 元,但是后来和一朋友聊天时聊到这个项目能为用户提供什么价值的问题,后来想想目前这个项目能给用户提供的价值是有限的,所以就调为免费的了。
Star ! Star ! Star !
Android 的界面布局与 iOS 版基本保持一致,但均采用了原生的控件实现,这里就不放截图了。
快速获取(自动识别系统): http://a.app.qq.com/o/simple.jsp?pkgname=io.daza.app
已上架多个国内主流应用市场
以下是我觉得比较值得分享的小技巧。
对于我来说 UI 才是最头痛的,在没有设计师帮忙的情况下一切都得自己来了,下面是我在做 UI 时的一些经验。
我在项目里使用了 Material Design 提供的配色( Blue Grey )和图标,在两个系统上看起来都非常的和谐。
使用第三方服务就是为了减少研发成本,但一定要慎重选用。下面介绍这个项目使用的一些第三方服务。
使用了 Docker 镜像构建,自有主机功能。 当前项目已经完全实现自动部署。
使用了 ECS 云主机
使用了 云存储,免费 SSL 证书
使用了推送服务
用于统计
用于 Crash 收集
广告
使用了 REST 风格进行设计,每个接口所返回的数据结构均保持一致。
数据结构示例:
{
"code": 0,
"message": "...",
"errors": [
{
"code": 10000,
"field": "user",
"message": "用户 不存在。"
}
],
"pagination": {
"total": 10,
"per_page": 10,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 10
},
"data": {
...
}
}
当错误码不为 0 时代表发生错误。
当发生多个错误时返回错误列表,客户端根据列表返回的进行相应的处理。
仅当 data 字段为数组时才返回。
"total": 总数
"per_page": 每页显示数量
"current_page": 当前页码
"last_page": 最后一页面页码
"from": 开始 Id
"to": 结束 Id
在实现时使用泛型对 data 进行处理。
泛型数据处理示例( Java ):
public class Result<T> {
private int code;
private String message;
private List<Error> errors;
private Pagination pagination;
private T data;
public Result() {
}
public boolean isSuccessful() {
return this.code == 0;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<Error> getErrors() {
return errors;
}
public void setErrors(List<Error> errors) {
this.errors = errors;
}
public Pagination getPagination() {
return pagination;
}
public void setPagination(Pagination pagination) {
this.pagination = pagination;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
// 当 data 为 User 时的示例
new Result<User>();
// 当 data 为 User 列表时的示例
new Result<ArrayList<User>>();
文章详情页面因为排版相关原因,并没有采用原生的开发方式,而是直接加载一个外部链接
外部链接:
https://daza.io/in-app/articles/{id}
因为 WebView 此时是没有保存用户状态的,所以需要将客户端的用户登录 Token 相关信息传递给 WebView ,即在加载完毕后执行 JavaScript 代码写入。
Java:
// 开启 JavaScript 及 localStorage 支持
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
// 页面加载完毕后将相关数据保存到 localStorage 里。
public void onPageFinished(WebView view, String url) {
String script = "javascript:";
if (Auth.check()) {
script += "localStorage.setItem('auth.id', '" + Auth.id() + "');\n";
script += "localStorage.setItem('auth.user', '" + Auth.user().toJSONString() + "');\n";
script += "localStorage.setItem('auth.jwt_token', '" + Auth.jwtToken().toJSONString() + "');\n";
} else {
script += "localStorage.clear();\n";
}
mWebView.loadUrl(script);
}
Swift:
func webViewDidFinishLoad(webView: UIWebView) {
if (!Auth.check()) {
return
}
let standardUserDefaults = NSUserDefaults.standardUserDefaults()
let authId = Auth.id();
let authUser = standardUserDefaults.stringForKey("auth.user")
let authJwtToken = standardUserDefaults.stringForKey("auth.jwt_token")
var script = ""
script += "localStorage.setItem('auth.id', '\(authId)');\n"
script += "localStorage.setItem('auth.user', '\(authUser!)');\n"
script += "localStorage.setItem('auth.jwt_token', '\(authJwtToken!)');\n"
webView.stringByEvaluatingJavaScriptFromString(script)
}
完整代码: https://github.com/lijy91/daza-ios/blob/master/Daza/Controllers/InAppBrowserController.swift
支持 DeepLink 后在 WebView 里直接可以通过自定义的 URL 来打开相应的页面,避免与 WebView 更麻烦的操作。
目前支持的链接:
daza://users/{user_id}
daza://topics/{topic_id}
daza://articles/{article_id}
daza://articles/{article_id}/comments
由于安卓的 WebView 不支持这个 DeepLink ,所以需要做一些处理:
public WebViewClient mWebViewClient = new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("daza://")) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
}
目前正处于自由职业的状态,如果有 API 或者客户端的需求欢迎加我微信
如果你有什么好想法想告诉我,或者想加入讨论组(注明加入讨论组),请加我微信。
如果你觉得我的工作对你有帮助,那你可以为项目捐赠运营费用。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.