「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)和图标,在两个系统上看起来都非常的和谐。
使用第三方服务就是为了减少研发成本,但一定要慎重选用。下面介绍这个项目使用的一些第三方服务。
使用了 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": {
...
}
}
"total": 总数
"per_page": 每页显示数量
"current_page": 当前页码
"last_page": 最后一页面页码
"from": 开始Id
"to": 结束Id
泛型数据处理示例(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 或者客户端的需求欢迎加我微信
如果你有什么好想法想告诉我,或者想加入讨论组(注明加入讨论组),请加我微信。
如果你觉得我的工作对你有帮助,那你可以为项目捐赠运营费用。