Based on Variant Response with Ruby on Rails, and the Browser gem for device differentiation, using responsive design and Turbolinks to optimize user experience.
2.5 Individual?
- 1 Full Stack (Me ^_^)
- 1 Ruby Programmer
- 0.5 Front-end Developer (Part-time Product Manager)
Cross-Terminal?
- Computer: Browser, WeChat for PC (PC version of WeChat supports WeChat login)
- Tablet: Browser, App (Android & iOS), WeChat
- Mobile: Browser, App (Android & iOS), WeChat
These terminals are not only used for access but also need to support push notifications and payments:
- Notification Channels: Email, SMS, WeChat, App Push
- Payment Channels: Alipay, WeChat Pay, UnionPay
Solutions
- Minimize development work as much as possible (limited personnel)
- Make the most of existing RoR technologies
- Differentiate specific terminals based on User Agent information
Starting from RoR
- Use Turbolinks to optimize web page loading experience
- Avoid using front-end MVC frameworks to increase workload
- Use responsive design + partial page Variant Response
- Do not create separate pages for each terminal
Differentiate Terminals Based on Browser
- The dual meaning of browser: web browser and browser gem
- Each terminal has its own User Agent
- Extend the browser gem to determine the current terminal type
- Print the terminal type to the body class so that CSS can adjust styles accordingly
Specific Steps
1. Use and Extend the browser gem to Determine Terminal Type
Browser::NAMES[:smileback] = 'SmileBack' # Our app's custom User Agent identifier
Browser::NAMES[:wechat] = 'Wechat'
Browser::NAMES[:desktop] = 'Desktop'
class Browser
module Meta
class Smileback < Base
def meta
'smileback' if browser.smileback?
end
end
class Wechat < Base
def meta
'wechat' if browser.wechat?
end
end
class Desktop < Base
def meta
'desktop' if browser.desktop?
end
end
end
module Consoles
def smileback?
!(ua =~ /smileback/i).nil?
end
def wechat?
!(ua =~ /MicroMessenger/i).nil?
end
def desktop?
!mobile? && !wechat? && !smileback?
end
end
end
2. Add Browser Information to the HTML Body Class for Easy CSS Application
<body class="<%= Browser.new(ua: request.env['HTTP_USER_AGENT']).to_s %>"> <!-- The class will output something like chrome modern mac webkit desktop or iphone ios mobile modern other safari safari5 webkit --!>
body { /* Default style */ }
body.desktop { /* Desktop browser custom style */ }
body.mobile { /* Mobile browser custom style */ }
body.wechat { /* WeChat custom style */ }
3. Use Variant Response for Pages with Significant Differences to Create Two or More Sets of Views
# application_controller.rb
before_action :detect_browser
private
def detect_browser
request.variant = :mobile if Browser.new(ua: request.env['HTTP_USER_AGENT']).mobile?
end
Pages that need to be split, create in the following format:
app/views/pages/home.erb
app/views/pages/home.html+mobile.erb # The file name format is response format + device name
4. Add Helper for Complex Cases, Such as Payment
# application_helper.rb
def browser
@_browser ||= Browser.new(ua: request.env['HTTP_USER_AGENT'])
end
/ Too lazy to convert to erb format, the following is in slim format
- if browser.smileback?
a.button href="jdxlsmileback://recharges/#{resource.id}/pay" Alipay Payment
= link_to 'UnionPay Payment', pay_recharge_path(resource, unionpay: true), 'data-no-turbolink' => true
- elsif browser.wechat?
- if current_user.weixin_id
= link_to 'WeChat Pay', '#', id: 'wepay', class: 'button'
= link_to 'UnionPay Payment', pay_recharge_path(resource, unionpay: true), 'data-no-turbolink' => true
- else
= link_to 'UnionPay Payment', pay_recharge_path(resource, unionpay: true), 'data-no-turbolink' => true, class: 'button'
- elsif browser.mobile?
= link_to 'Alipay Payment', pay_recharge_path(resource, alipay: true), class: 'button', 'data-no-turbolink' => true
= link_to 'UnionPay Payment', pay_recharge_path(resource, unionpay: true), 'data-no-turbolink' => true
- else
= link_to 'Alipay Payment', pay_recharge_path(resource, alipay: true), class: 'button', 'data-no-turbolink' => true
= link_to 'WeChat Pay', pay_recharge_path(resource, scan_wepay: true)
= link_to 'UnionPay Payment', pay_recharge_path(resource, unionpay: true), 'data-no-turbolink' => true
Other Experiences
- For the iOS App, we used a shell with WKWebView, which has better performance than UIWebView but also more restrictions. You can Google for specifics.
- For the Android App, we used the default WebView and haven’t found a better alternative yet.
- We previously encapsulated our own payment channels, but now we find Ping++ to be quite good as well, so you might want to give it a try.