Thursday, October 29, 2015

[UNITY] Vấn đề về dung lượng file build iOS

Như mọi người biết thì apple giới hạn dung lượng tối đa có thể download game/app từ apple store bằng Cellular (3G/4G/LTE) là 100MB. Nếu Unity để phát triển game thì dung lượng của game quả là 1 vấn đề không hề nhỏ, nhất là với game social. Dung lượng quá lớn vượt quá 100MB, user sẽ phải dùng đến wifi để có thể download được game của bạn. Điều đó sẽ làm giảm lượng download game của bạn.

Có nhiều cách để có thể giảm dung lượng của game. Nhưng với những game social, resource (ảnh, audio) rất lớn, việc tối ưu hoá file dưới 100MB là điều bất khả thi. Unity có hỗ trợ Assetbundle để giải quyết vấn đề này. Developer có thể đưa 1 phần resource lên server và user có thể tải phần đó sau khi mở game.

Quay trở lại vấn đề về dung lượng file. Vậy cho bao nhiều resource lên server để download sau khi user mở game là đủ? Nếu lạm dụng Assetbundle nhiều quá sẽ làm cho lượng resource phải tải về từ server của mình là khá lớn. Server sẽ chịu tải nhiều. Thường thì chúng ta sẽ cố gắng để cân bằng 2 điều đó là dung lượng file dưới 100MB và lượng resource download bằng Assetbundle không quá lớn.

Sau khi build làm thế nào để tính được dung lượng file ipa?
Mình giới thiệu 1 cách hiện giờ mình vẫn đang áp dụng cho game của mình.

Đầu tiên bạn build file ipa (release version). Ví dụ là `mygame.ipa`

Dùng Terminal gõ lệnh: ls -la {đường đẫn đến file}

vd: ls -la mygame.ipa

Kết quả sẽ hiện:

-rw-r--r--+ 1 guest-user  staff  62113983 10 29 11:24 mygame.ipa

Tiếp tục bạn gõ: unzip {đường đẫn đến file}

vd: unzip mygame.ipa
Lúc này file ipa sẽ được unzip.

Unzip xong bạn sẽ thấy file {app-bundle}.app trong thư mục Payload vừa được unzip
Tiếp theo gõ : otool -l Payload/{app-bundle}.app/{app-bundle} | grep cryptsize

vd: otool -l Payload/my-game.app/my-game | grep cryptsize

Kết quả:
    cryptsize 29884416
    cryptsize 34668544

Tính tổng:

62113983 + 29884416 + 34668544 = 126,666,943 bytes

File ipa có size ~ 100MB sau khi up lên apple store theo tính toán như ở trên có kết quả là 125,687,674 bytes

Dựa vào so sánh giữa 2 kết quả này ta thấy file mygame.ipa dung lượng đã vượt qua 100MB

126,666,943 - 125,687,674 = 979,269 ~ 0.93MB

Chúng ta sẽ phải đưa bớt resource thành Assetbundle hoặc tối ưu lại chúng.

Mong là bài viết này hữu ích cho các bạn.





Sunday, May 10, 2015

[Tản Mạn] Thủ tục bảo lãnh vợ/chồng sang Nhật - kĩ sư 5/2015

Các tài liệu cần nộp khi làm đơn bảo lãnh người thân (vợ) sang Nhật của
kĩ sư:

1. Chuẩn bị từ Việt Nam:
①. Giấy kết hôn dịch tiếng Nhật và công chứng……..................…………..1 bản.
②. Hộ chiếu của vợ photocopy (không cần công chứng)…................…….1 bản.
③. Ảnh hồ sơ 3cmx4cm của vợ nền xanh hoặc trắng, không đổ bóng……1 tấm.
Bản công chứng và ảnh làm trong vòng 6 tháng đến thời điểm nộp đơn.

2. Chuẩn bị tại Nhật:
④. Giấy chứng nhận là nhân viên chính của công ty (在職証明書).
Xin tại công ty………………………………………....……………..1 bản.
⑤. Bảng lương trong 1 năm.
Xin tại công ty có dấu công ty là tốt nhất……..…....……………..1 bản.
⑥. Giấy chứng nhận đóng thuế có 2 loại:
- 納税証明
(1 の年度,税目につき1 件 300 円)................................................1 bản.
- 課税証明
(1 件 300 円)………………………...........................……………....1 bản.
Xin tại 市役所.
Trong trường hợp bạn nào mới sang Nhật làm việc thì chưa có giấy chứng nhận thuế thì phải ra ngân hàng xin lịch sử giao dịch.
納税証明: năm đầu chưa phải đóng nên chưa có.
⑦. Giấy chứng nhận đăng kí nguyên bản của thẻ ngoại kiều,
登録原票記載事項証明書
とうろくげんぴょうきさいじこうしょうめいしょ
giờ có 1 tên khác
(1件 300 円)……….......................................................………… 1 bản.
Xin tại 市役所
しやくしょ
.
⑧. Hộ chiếu của mình photocopy (không cần công chứng)……..1 bản.
⑨. Thẻ ngoại kiều photocopy (không cần công chứng)……....... .1 bản.
⑩. Phong bì loại thường (書留の封筒) có dán sẵn tem (tem 392 yen).
và ghi rõ địa chỉ nhận thư của mình. Mua tại コンビニ (Family
mart..) ....1 bản. Nên mua loại phong bì to để không bị nhàu giấy.
⑩. Đơn xin cấp giấy chứng minh thừa nhận tư cách định cư.
在留資格認定証明書交付申請書
Là mẫu dưới đây đã được download tại trang chủ của bộ tư pháp Nhật
http://www.immi-moj.go.jp/english/tetuduki/kanri/shyorui/01-format.html. (mục thứ 11 nhé)
Tư cách của người viết đơn là vợ, người được ủy quyền viết đơn là mình có đóng
dấu của mình. Và ảnh 3x4 đã chuẩn bị của vợ “③” được dán vào đây.
Mẫu đơn này được viết trước ở nhà.
Và thư mời download tại đây http://www.moj.go.jp/content/000007382.pdf
Các giấy tờ chuẩn bị tại Nhật làm trong vòng 3 tháng đến thời điềm nộp
đơn.
Giấy ⑥, ⑦.  xin tại 市役所
chỉ mất 30 phút. 市役所
làm việc từ 8h30~
17h15 thứ 2 đến thứ 6.

※ Khi đầy đủ các mẫu ① ~ ⑩ thì tất cả được nộp tại cục quản lý xuất
nhập cảnh,入管(東京入国管理局__
địa chỉ:
Tokyo: 
東京都港区港南5-5-30). 
Yokohama:
神奈川県横浜市
金沢区鳥浜町10−7
東京入国管理局横浜支局

làm việc ừ 9h00 ~12h00 & 13h00 ~ 16h00 thứ 2 đến thứ 6. Sau khi nộp nhận
lại biên lai đã thu là xong. 
Thời gian xét đơn trong vòng 3 tháng (có thể nhanh hơn, như mình là 2 tuần).
Ai ở Yokohama thì không nên làm ở cục xuất nhập cảnh ở trên tokyo vì sẽ đông và đợi lâu
Nếu không có vấn đề gì, sẽ được nhận giấy OK gửi về theo bưu điện. Chỉ cần gửi Certificate of Eligibility để vợ ở Việt Nam nộp để xin visa (mình gửi dịch vụ EMS của bưu điện, mất 3-4 ngày đến nhà, mất 900 yen)

* Ở nhà xin visa thì cần 5 loại giấy tờ
Certificate of Eligibility (bạn gửi từ Nhật về) : bản chính và bản photo không cần công chứng
- Hộ chiếu của vợ
- Đăng kí kết hôn: bản chính + photo
- Đơn xin visa down trên trang chủ của đại sứ quán Nhật tại VN.
- Ảnh 3x4 đằng sau ghi tên

Tuesday, January 27, 2015

[NOTE] How to Deal With an iPhone Crash Report

Kudos to the app review team at Apple, they found a crasher in the update to Emergency List that I recently submitted. They even took the time to step through and document what they did exactly to reproduce the error.
From their email:
1. Launch app connected to a network
2. Tap Emergency List
3. Tap the Add button
4. Tap Add from Address Book
5. App crashes

Please refer to the attached crash logs.
They even sent two crash logs to help find the problem.

Reading the Crash Logs

The crash logs by themselves are very difficult to read. Below is a segment:
Thread 0 Crashed:
0   libSystem.B.dylib               0x3293f98c 0x328c1000 + 518540
1   libSystem.B.dylib               0x3293f97c 0x328c1000 + 518524
2   libSystem.B.dylib               0x3293f96e 0x328c1000 + 518510
3   libSystem.B.dylib               0x3295461a 0x328c1000 + 603674
4   libstdc++.6.dylib               0x30a143b0 0x309cf000 + 283568
5   libobjc.A.dylib                 0x3347a858 0x33475000 + 22616
6   libstdc++.6.dylib               0x30a12776 0x309cf000 + 276342
7   libstdc++.6.dylib               0x30a127ca 0x309cf000 + 276426
8   libstdc++.6.dylib               0x30a12896 0x309cf000 + 276630
9   libobjc.A.dylib                 0x33479714 0x33475000 + 18196
10  CoreFoundation                  0x3355ab86 0x33534000 + 158598
11  CoreFoundation                  0x3355ab24 0x33534000 + 158500
12  Foundation                      0x326cf9ae 0x3267e000 + 334254
13  Foundation                      0x32685760 0x3267e000 + 30560
14  EmergencyNumbers                0x0000641c 0x1000 + 21532
15  EmergencyNumbers                0x000060d2 0x1000 + 20690
16  UIKit                           0x31c63aa4 0x31c17000 + 314020
17  UIKit                           0x31c7aec0 0x31c17000 + 409280
18  UIKit                           0x31c7ace0 0x31c17000 + 408800
19  UIKit                           0x31c7abde 0x31c17000 + 408542
20  UIKit                           0x31c7a784 0x31c17000 + 407428
21  UIKit                           0x31c7a59c 0x31c17000 + 406940
22  UIKit                           0x31c7a4e0 0x31c17000 + 406752
23  UIKit                           0x31c65df4 0x31c17000 + 323060
24  UIKit                           0x31c4a574 0x31c17000 + 210292
25  QuartzCore                      0x30039004 0x30030000 + 36868
26  QuartzCore                      0x30038e1c 0x30030000 + 36380
27  QuartzCore                      0x3003893c 0x30030000 + 35132
28  QuartzCore                      0x300386a2 0x30030000 + 34466
29  QuartzCore                      0x3003e02a 0x30030000 + 57386
30  CoreFoundation                  0x33543b50 0x33534000 + 64336
31  CoreFoundation                  0x3358aa32 0x33534000 + 354866
32  CoreFoundation                  0x3358a356 0x33534000 + 353110
33  GraphicsServices                0x3352bb2c 0x33528000 + 15148
34  GraphicsServices                0x3352bbd8 0x33528000 + 15320
35  UIKit                           0x31c19768 0x31c17000 + 10088
36  UIKit                           0x31c1846c 0x31c17000 + 5228
37  EmergencyNumbers                0x000020b4 0x1000 + 4276
38  EmergencyNumbers                0x00002070 0x1000 + 4208
All I can read from this is that lines 14 and 15 above in the stack trace is where the crash happened in MY code. But what does 0x0000641c mean?
Fortunately, I had the dSYM file for the release that they reviewed handy. I ran the following command against it:
dwarfdump --lookup 0x0000641c -arch armv6 EmergencyNumbers.app.dSYM
This command would tell me at what line the app failed. And here it is:
Line table file: 'AddressBookLookupTableViewController.m' line 60, 
column 0 with start address 0x000000000000641a

Determining the cause of the Crash

Going to that file and line in the source code reveals:
1
2
3
CFStringRef cfName = ABRecordCopyCompositeName(person);
aName = [NSString stringWithString:(NSString *)cfName];
CFRelease(cfName);
So the crash is happening in the NSString stringWithString. If cfName is equal to nil, this line of code will crash.

Understanding the Error

But this error makes no sense to me. In line 59, cfName is populated with the composite name from a valid address book record (person is not nil). According to Apple’s reference documentation, ABRecordCopyCompositeName returns:
For group records: The value of the group name property
    (kABGroupNameProperty).
For person records: The concatenated value of these properties:
    Prefix, Suffix, Organization, First name, and Last name.
I just assumed that all contact records in the address book would actually have a name of some kind. And I was wrong! It turns out that it is possible to create address book entries with none of the above fields filled in. And my code should support that.

The Fix

Easy. If cfName is nil, use a default name called “No Name”, just like the address book on Mac OS X. I noticed that the iPhone address book works differently in that it has a cascade of which fields it shows before coming up with “No Name”, but that is not necessary for my app.
1
2
3
4
5
6
7
8
9
10
11
// It is possible for address books to have no name entries
CFStringRef cfName = ABRecordCopyCompositeName(person);
if (cfName != nil)
{
  aName = [NSString stringWithString:(NSString *)cfName];
  CFRelease(cfName);
}
else
{
  aName = @"No Name";
}

Lessons Learned

  • Always save the dSYM file from each release so that you can drill on crash reports.
  • Always save a snapshot of each release version in source code control so you can pull out the right code base to match the crash report.
  • Watch out for assumptions when writing code. I assumed all address book contacts would have names. I was wrong!
Once again, thanks Apple Review People for catching this.
(source) http://noverse.com/blog/2010/03/how-to-deal-with-an-iphone-crash-report/