Skip to main content


Flutter: Fixing Firebase header not found with Notification Service Extension

If you follow the FCM tutorial Send an image in the notification payload and encountered this error message:
'FirebaseMessaging/FirebaseMessaging.h' file not found You are on the right place, I'm going to show you how to fix it.

My app was working fine but one day it stopped compiling. Apparently Flutter 1.20 changed the way it uses CocoaPod so the service extension no longer has the proper library configured. After some tinkering, I came up with this pod config, it has to be added to ios/Podfile below the main Runner target. target 'FcmImage' do use_frameworks! use_modular_headers! require File.expand_path('../.symlinks/plugins/firebase_core/ios/firebase_sdk_version.rb', __FILE__) firebase_sdk_version = firebase_sdk_version! pod 'Firebase/Messaging', "~> #{firebase_sdk_version}" end FcmImage is my extension name, replace it with yoursWe can use a hardcoded version for Firebase/Messaging pod but doing so may require further…
Recent posts

Making GIF of iOS Simulator without additional apps

This is how I did it: open Terminal and execute this command:

xcrun simctl io booted recordVideo \
  --code=h264 \
  --force "$( date +%Y%m%d%H%M%S ).mov"

Running this will record the Simulator screen until you press `Control+C`. The filename will be something like ``. The next step is to convert this video into GIF, FFMPEG is required for this. You can either install it via Homebrew but I prefer running it in a Docker container, something like this:

docker run --rm -it -v $PWD:/data -w /data --entrypoint /bin/bash jrottenberg/ffmpeg

Once you have FFMPEG installed or are inside the container, execute this command:

ffmpeg -i \
  -vf "fps=fps=5,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \

I have played around with the command line arguments and came up with those. Basically it will create a decent GIF to use in issue report etc. Because of the low frame rate, it won't be very s…

Running phpinfo to test Kubernetes ingress and Let's Encrypt certificate

For new cluster, I usually deploy a simple phpinfo app to test that the happy-path works as expected. The PHP service and deployment is pretty simple:

The Docker image is basically a php:apache image with a single index.php file.

Next, setup the ingress and issuer (I'm using ingress-nginx and cert-manager FYI):

And voila.

Amazon SES notes

Amazon IAM policy to restrict sending email from a single address{
  "Version": "2012-10-17",
  "Statement": [
"Effect": "Allow",
    "Action": "ses:SendRawEmail",
    "Resource": "*",
    "Condition": {
      "StringLike": {
        "ses:FromAddress": ""

Replace `` with `*` to allow sending from any addresses.
Generate SMTP password from the secret access key Official document is available at Usage is like this:

./ --secret DmxxxOY --region us-west-2

Test SMTP credentials I use the swaks script (source:

brew install swaks

swaks -tls --to \
  --from \
  --server \
  --auth-user AKxxxOP

If everything is setup correctly, you should receive the test email in your inbox.

Configure XenForo 2 to use FTP adapter for external and internal data storage

XenForo 1 needs an add-on to use remote storage for data (useful in container environments) but XenForo 2 supports FTP out of the box. Just put something like these in config.php:

$config['fsAdapters']['data']=function(){returnnew\League\Flysystem\Adapter\Ftp(['host'=>'','password'=>'password','username'=>'data',]);};$config['externalDataUrl']=function($externalPath,$canonical){return'' .$externalPath;};$config['fsAdapters']['internal-data']=function(){returnnew\League\Flysystem\Adapter\Ftp(['host'=>'','password'=>'password','username'=>'internal_data',]);};

Cord cutting là gì và vì sao mình chọn không dùng truyền hình cáp

Ngày xửa ngày xưa, mua tivi xong chỉ cần cắm ăngten râu vào cái lỗ tròn tròn là xem được Tây du ký. Sau đấy sờ râu với cắm lại đủ kiểu mà xem Cảnh sát hình sự vẫn nhiễu nên từ đó mặc định có tivi là lắp luôn truyền hình cáp (hồi đầu là 45k/tivi/tháng, toàn trả tiền một cái nhưng cho thêm anh lắp đặt ít tiền để ảnh làm giùm bộ tách, xem thêm ở hai ba tivi nữa). Ngày nảy ngày nay, cáp rồi nhưng còn quẩy thêm bộ giải mã để xem các kênh hát đê (cái cục thì có thể tặng nhưng tiền gói thì thêm 50k/tivi/tháng). Đến khổ, càng hiện đại thì càng ăn tiền 😭

Năm ngoái, đứng trước quyết định vô cùng lớn lao khi... lắp tivi, vợ chồng mình đã dấn thân vào con đường khá mới mẻ và (có lẽ) trở thành một trong những cord cutters tiên phong ở Sài Gòn! Hiểu theo nghĩa đen thì cord cutting là việc cầm kéo cắt cái dây truyền hình cáp cái bụp. Sở dĩ không xài truyền hình cáp vì bọn mình thấy bỏ ra một khoản tiền vài trăm ngàn một tháng cho cáp là không hề cần thiết. Mang tiếng là có hàng trăm kênh nhưng thực…

Facebook author metatag and app-scoped ID

Not sure if this is a bug or the desired behavior but apparently Facebook does not understand their own app-scoped user ID if it is used in a "article:author" meta tag. Debugging the page will yield an error that says the provided value ( is not a profile. Of course if you go to that url, it will redirect to the correct user profile page. It just doesn't work for sharing, probably for security reason.

In our case, we have to let user enter their own username/id and use that for the meta tag. Not the best user friendly experience but it works for now...